SPA-3~shell控制器下錨已經應用狀態管理
單頁應用因為是用javascript來生成HTML,所以我們把所有的外部指令碼放在head區塊中,以便改進組織結構和易讀性。
一般在一個單獨的html檔案中開發功能容器的HTML和CSS。只有把容器調整為我們喜歡的那樣之後,才把程式碼移至shell的css和javascript檔案。
1.當發生歷史事件的時候,更改錨,同時更改程式狀態。
spa.shell=(function(){
//------BEGIN MUDULE SCOPE VARIABLES------
//靜態配置值放在configMap變數中
var
configMap={
//縮緊html字元,這樣有利於理解和維護
main_html:String()
//嵌入logo,賬戶設定和head容器中的搜尋框
+'<div class="spa-shell-head">'
+'<div class="spa-shell-head-logo"></div>'
+'<div class="spa-shell-head-acct"></div>'
+'<div class="spa-shell-head-search"></div>'
+'</div>'
//將導航(nav)和content容器放在主容器裡面
+'<div class="spa-shell-main">'
+'<div class="spa-shell-main-nav"></div>'
+'<div class="spa-shell-main-content"></div>'
+'</div>'
//建立footer容器
+'<div class="spa-shell-foot"></div>'
//將chat容器固定在外部容器的右下角
+'<div class="spa-shell-chat"></div>'
//建立modal容器,漂浮在其它內容的上面
+'<div class="spa-shell-modal"></div>',
chat_extend_time:1000,
chat_retract_time:300,
chat_extend_height:450,
chat_retract_height:15,
chat_extended_title:'click to retract',
chat_retracted_title:'click to extend'
},
//將在整個模組中共享的動態資訊放在stateMap變數中
stateMap={
$container:null,
is_chat_retracted:true
},
//將jQuery集合快取在jqueryMap中
jqueryMap={},
//宣告所有模組作用域的變數,很多都是在之後賦值
setJqueryMap,initModule,toggleChat,onClickChat;
//------END MODULE SCOPE VARIABLES
//------BEGIN UTILITY METHODS
//unility Method 保留區塊,這些函式不和頁面元素互動
//------END UTILITY METHODS------
//------BEGIN DOM METHODS------
//begin DOM method /setJqueryMap/
//將建立和操作頁面元素的函式放在“DOM Method”區塊中
//使用setJqueryMap來快取jQuery集合。幾乎編寫的每個shell和功能模組都應該有這個函式
//用途是可以大大地減少jQuery對文件的遍歷次數,能夠提高效能.
setJqueryMap=function(){
var $container=stateMap.$container;
jqueryMap={
$container:$container,
$chat:$container.find('.spa-shell-chat')
};
};
//end DOM mothod /setJqueryMap/
//begin DOM method /toggleChat/
//Purpose :Extends or retracts chat slider
//Arguments:
// *do_extend - if true,extends slider;if false retracts
// *callback - optional function to execute at end of animation
//Settings
// *chat_extend_time,chat_retract_time
// *chat_extend_height,chat_retract_height
//Returns : boolean
// *true - slider animation activated
// *false - slider animation not activated
//State : sets stateMap.is_chat_retracted
// *true - slider is retracted
// *false - slider is extended
toggleChat=function(do_extend,callback){
var
px_chat_ht=jqueryMap.$chat.height(),
is_open=px_chat_ht===configMap.chat_extend_height,
is_closed=px_chat_ht===configMap.chat_retract_height;
is_sliding=!is_open&&!is_closed;
//avoid race condition
if(is_sliding){return false;}
//begin extend chat slider
if(do_extend){
jqueryMap.$chat.animate(
{height:configMap.chat_extend_height},
configMap.chat_extend_time,
function(){
jqueryMap.$chat.attr(
'title',configMap.chat_extended_title
);
stateMap.is_chat_retracted=false;
if(callback){callback(jqueryMap.$chat);}
}
);
return true;
}
//End extend chat slider
//begin restract chat slider
jqueryMap.$chat.animate(
{height:configMap.chat_retract_height},
configMap.chat_retract_time,
function(){
jqueryMap.$chat.attr(
'title',configMap.chat_retracted_title
);
stateMap.is_chat_retracted=true;
if(callback){callback(jqueryMap.$chat);}
}
);
return true
//end retract chat slider
}
//End Dom mothod /toggleChat/
//------END DOM METHODS------
//------BEGIN EVENT HANDLERS------
//為jquery事件處理函式保留的“Event Handlers”區塊
onClickChat=function(event){
if(toggleChat(stateMap.is_chat_retracted)){
$.uriAnchor.setAnchor({
chat:(stateMap.is_chat_retracted?'open':'closed')
});
}
toggleChat(stateMap.is_chat_retracted);
return false;
}
//------END EVENT HANDLERS------
//------BEGIN PUBLIC METHODS------
//將公開的方法放在public method 區塊中
//begin public method /initModule/
//建立initModule公開方法,用於初始化模組
initModule=function($container){
//load HTML and map jQuery collections
stateMap.$container=$container;
$container.html(configMap.main_html);
setJqueryMap();
//initialize chat slider and bind click handler
stateMap.is_chat_retracted=true;
jqueryMap.$chat
.attr('title',configMap.chat_retracted_title)
.click(onClickChat);
}
//end public method /initModule/
//顯式地匯出公開方法,以對映(map)的形式返回。目前可用的只有initModule
return {initModule:initModule};
//------END PUBLIC METHODS------
}());
我們需要確保,當錨變化的時候,只改變應用需要改變的地方。這會使應用快很多,當部分頁面內容沒必要清除和重新渲染時,避免了發生煩人的“閃爍”現象。
2.使用錨來驅動應用狀態
我們希望的是始終讓錨元件來驅動應用狀態:
1.當發生歷史事件時,更改URI的錨元件,以便體現更改的狀態
--接收事件的處理程式呼叫shell的工具方法來改變錨
--然後事件處理程式退出
2.Shell的hashchange事件處理程式注意到了URI的變化並按它行事。
--將當前狀態和新的錨表示的狀態做比較
--根據比較確定的結果,嘗試更改需要更改的應用部分
--如果不能處理請求的變化,則保持當前的狀態,並恢復錨,以便和狀態匹配。
spa.shell=(function($){
//------BEGIN MODULE SCOPE VARIABLE------
var
configMap={
anchor_schema_map:{
chat:{open:true,closed:true}
},
//縮緊html字元,這樣有利於理解和維護
main_html:String()
//嵌入logo,賬戶設定和head容器中的搜尋框
+'<div class="spa-shell-head">'
+'<div class="spa-shell-head-logo"></div>'
+'<div class="spa-shell-head-acct"></div>'
+'<div class="spa-shell-head-search"></div>'
+'</div>'
//將導航(nav)和content容器放在主容器裡面
+'<div class="spa-shell-main">'
+'<div class="spa-shell-main-nav"></div>'
+'<div class="spa-shell-main-content"></div>'
+'</div>'
//建立footer容器
+'<div class="spa-shell-foot"></div>'
//將chat容器固定在外部容器的右下角
+'<div class="spa-shell-chat"></div>'
//建立modal容器,漂浮在其它內容的上面
+'<div class="spa-shell-modal"></div>',
chat_extend_time:1000,
chat_retract_time:300,
chat_extend_height:450,
chat_retract_height:15,
chat_extended_title:'click to retract',
chat_retracted_title:'click to extend'
},
//將在整個模組中共享的動態資訊放在stateMap變數中
stateMap={
$container:null,
anchor_map:{},
is_chat_retracted:true
},
//將jQuery集合快取在jqueryMap中
jqueryMap={},
copyAnchorMap,setJqueryMap,toggleChat,
changeAnchorPart,onHashchange,
onClickChat,initModule;
//------END MODULE SCOPE VARIABLES------
//------BEGIN UTILITY METHODS------
//Returns copy of stored anchor map;minimizes overhead(降低難度)
copyAnchorMap=function(){
return $.extend(true,{},stateMap.anchor_map);
}
//------END UTILITY METHODS------
//------BEGIN DOM METHODS------
//begin DOM method /setJqueryMap/
//將建立和操作頁面元素的函式放在“DOM Method”區塊中
//使用setJqueryMap來快取jQuery集合。幾乎編寫的每個shell和功能模組都應該有這個函式
//用途是可以大大地減少jQuery對文件的遍歷次數,能夠提高效能.
setJqueryMap=function(){
var $container=stateMap.$container;
jqueryMap={
$container:$container,
$chat:$container.find('.spa-shell-chat')
};
};
//end DOM mothod /setJqueryMap/
//begin DOM method /toggleChat/
//Purpose :Extends or retracts chat slider
//Arguments:
// *do_extend - if true,extends slider;if false retracts
// *callback - optional function to execute at end of animation
//Settings
// *chat_extend_time,chat_retract_time
// *chat_extend_height,chat_retract_height
//Returns : boolean
// *true - slider animation activated
// *false - slider animation not activated
//State : sets stateMap.is_chat_retracted
// *true - slider is retracted
// *false - slider is extended
toggleChat=function(do_extend,callback){
var
px_chat_ht=jqueryMap.$chat.height(),
is_open=px_chat_ht===configMap.chat_extend_height,
is_closed=px_chat_ht===configMap.chat_retract_height;
is_sliding=!is_open&&!is_closed;
//avoid race condition
if(is_sliding){return false;}
//begin extend chat slider
if(do_extend){
jqueryMap.$chat.animate(
{height:configMap.chat_extend_height},
configMap.chat_extend_time,
function(){
jqueryMap.$chat.attr(
'title',configMap.chat_extended_title
);
stateMap.is_chat_retracted=false;
if(callback){callback(jqueryMap.$chat);}
}
);
return true;
}
//End extend chat slider
//begin restract chat slider
jqueryMap.$chat.animate(
{height:configMap.chat_retract_height},
configMap.chat_retract_time,
function(){
jqueryMap.$chat.attr(
'title',configMap.chat_retracted_title
);
stateMap.is_chat_retracted=true;
if(callback){callback(jqueryMap.$chat);}
}
);
return true
//end retract chat slider
}
//End Dom mothod /toggleChat/
//Begin DOM method /changeAnchorPart/
//purpose : Changes part of the URI anchor component
//Arguments:
// *arg_map - The map describing what part of the URI anchor we want changed
//Returns : boolean
// *true - the Anchor portion of the URI was update
// *false - the Anchor portion of the URI could not be updated
//Action :
// The current anchor rep stored in stateMap.anchor_map.
// See uriAnchor for a discussion of encoding.
// This method
// *Creates a copy of this map using copyAnchorMap();
// *Modifies the key-values using arg_map.
// *Manages the distinction between independent and dependent values in the encoding
// *Attempts to change the URI using uriAnchor
// *Returns true on success , and false on failure.
//
changeAnchorPart=function(arg_map){
var
anchor_map_revise=copyAnchorMap(),
bool_return=true,
key_name,key_name_dep;
//Begin merge changes into anchor map
KEYVAL:
for(key_name in arg_map){
if(arg_map.hasOwnProperty(key_name)){
//skip dependent keys during iteration
if(key_name.indexOf('_')===0){
continue KEYVAL;
}
// update independent key value
anchor_map_revise[key_name] = arg_map[key_name];
//update independent key values
key_name_dep="_"+key_name;
if(arg_map[key_name_dep]){
anchor_map_revise[key_name_dep] = arg_map[key_name_dep]
}else{
delete anchor_map_revise[key_name_dep];
}
delete anchor_map_revise['_s'+key_name_dep]
}
}
//End merge changes into anchor map
//Begin attempt to update URI ; revert if not successful
try{
$.uriAnchor.setAnchor(anchor_map_revise);
}
catch(error){
//replace URI with existing state
$.uriAnchor.setAnchor(stateMap.anchor_map,null,true);
bool_return=false;
}
//End attempt to update URI
return bool_return;
};
// End DOM method /changeAnchorPart/
//------END DOM METHODS------
//------BEGIN EVENT HANDLERS------
//Begin Event handlers /onHashchange/
//Arguments:
// *event - jQuery event object.
//Settings:none
//Returns :false
//Action:
// *Parses the URI anchor component
// *Compares proposed application state with current
// *Adjust the application only where proposed state differs from existing
//
onHashchange=function(event){
var
anchor_map_previous=copyAnchorMap(),
anchor_map_proposed,
_s_chat_previous,_s_chat_proposed,
s_chat_proposed;
//attempt to parse anchor,$.uriAnchor.makeAnchorMap() always produce a addition
//key '_s_'+key ,such as _s_chat
try{anchor_map_proposed=$.uriAnchor.makeAnchorMap();}
catch(error){
$.uriAnchor.setAnchor(anchor_map_previous,null,true);
return false;
}
stateMap.anchor_map=anchor_map_proposed;
//convenience vars
_s_chat_previous=anchor_map_previous._s_chat;
_s_chat_proposed=anchor_map_proposed._s_chat;
//Begin adjust chat component if changed
if(!anchor_map_previous||_s_chat_previous!==_s_chat_proposed){
s_chat_proposed=anchor_map_proposed.chat;
switch(s_chat_proposed){
case 'open' :
toggleChat(true);
break;
case 'closed' :
toggleChat(false);
break;
default:
toggleChat(false);
delete anchor_map_proposed.chat;
$.uriAnchor.setAnchor(anchor_map_proposed,null,true);
}
}
// End adjust chat component if changed
return false;
};
//End Event handler /onHashchange/
//Begin Event handler /onHashchange/
onClickChat=function(event){
changeAnchorPart({
chat:(stateMap.is_chat_retracted?'open':'closed')
});
return false;
}
//End Event handler /onClickChat/
//------END EVENT HANDLERS------
//------BEGIN PUBLIC METHODS
//Begin Public method /initModule/
initModule=function($container){
//load HTML and map jQuery collections
stateMap.$container=$container;
$container.html(configMap.main_html);
setJqueryMap();
//initialize chat slider and bind click handler
stateMap.is_chat_retracted=true;
jqueryMap.$chat
.attr('title',configMap.chat_retracted_title)
.click(onClickChat);
// 配置uriAnchor外掛,用於檢測模式(schema)
//configure uriAnchor to use our schema
$.uriAnchor.configModule({
schema_map:configMap.anchor_schema_map
});
//Handler URI anchor change events
//this is done /after/ all feature modules are configured
//and initialized ,otherwise they will not be ready to handle
//the trigger event ,which is used to ensure the anchor
//is considered on-load
//
$(window)
.bind('hashchange',onHashchange)
.trigger('hashchange');
};
//End Public method /initModule/
return {initModule:initModule};
//------END PUBLIC METHODS------
}(jQuery));
相關文章
- 使用 Provider 管理 Flutter 應用狀態 (下)IDEFlutter
- 使用 Provider 管理 Flutter 應用狀態 (上)IDEFlutter
- Kubernetes有狀態應用管理——PetSet
- docker筆記28-stateful(有狀態應用副本集)控制器Docker筆記
- Redux複雜應用(一):淺談狀態管理Redux
- SHELL指令碼檢查Oracle DG備庫是否已經應用歸檔指令碼Oracle
- linux下利用curl監控web應用狀態LinuxWeb
- 使用 useState 管理響應式狀態
- PDM系統在技術狀態管理中的應用研究
- 用於管理應用程式得shell指令碼指令碼
- 探索FSM (有限狀態機)應用
- shell程式的結束狀態
- 狀態管理專用框架Scopes誕生框架
- 基於 Redux + Redux Persist 進行狀態管理的 Flutter 應用示例ReduxFlutter
- 前端狀態管理與有限狀態機前端
- Linux下用netstat檢視網路狀態、埠狀態Linux
- Flutter | 狀態管理Flutter
- Vuex狀態管理Vue
- ASP.NET Core 應用程式狀態ASP.NET
- Java應用異常狀態監測Java
- React 狀態管理:狀態與生命週期React
- 淺談前端的狀態管理,以及anguar的狀態管理庫前端
- Swift 專案總結 06 基於控制器的全域性狀態列管理Swift
- Flutter-狀態管理Flutter
- ⚠️Flutter的 狀態管理⚠️Flutter
- React的狀態管理React
- Flutter如何狀態管理Flutter
- react 狀態機管理React
- SAP BSP應用有狀態和無狀態行為差異比較
- Flutter開發日記-資料傳遞/狀態管理的方式和應用Flutter
- [譯] Flutter 中的原生應用程式狀態Flutter
- 32. http狀態碼 應用場景HTTP
- 使用NAS動態儲存卷建立有狀態應用
- 用SQL Server來進行會話狀態管理SQLServer會話
- Flutter 狀態管理之BLoCFlutterBloC
- Flutter 狀態管理實踐Flutter
- 理解資料狀態管理
- Flutter入門 - 狀態管理Flutter