這個模塊應該就是該書全篇的惟一一個模塊吧,後面差點兒所有的篇章都環繞這個模塊去實現的,只是就經過這一個模塊的實現和上線,也能體現單頁應用開發到公佈上線的整個過程,畢竟後面的數據。通訊。公佈什麼的都是通用的東西,應用其它部分全然可以參照這個‘聊天模塊’去實現。跟着做者的思路走一遍,也能熟知個大概。javascript
先看下成型圖吧,會不會有種很是老舊XP時代的感受,囧!php
!css
chat
內容該聊天模塊整體分下面幾塊:事實上都是跟着模版去實現的,差在詳細實現上而已html
涉及行爲處理:
1. 點擊標題欄。顯示或隱藏窗體。
2. hash 值的變化觸發聊天窗體的狀態變化;java
重點在 經過 hash 值(錨)的變化來管理聊天窗體顯示和隱藏。前面在shell裏面實現過,這裏主要拎出來做爲一個單獨模塊來說jquery
配置三大塊:shell
以前chat
模塊是直接在shell
模塊中實現的,爲了實現模塊化,下降依賴,從而把該模塊分離出來單首創建模塊文件:spa.chat.js
和對應的樣式和輔助文件等數據庫
configMap
瀏覽器
這裏包括了chat
模塊的基本配置,和所用到的模塊變量,來看下里面詳細都有些啥緩存
var configMap = {
// 模塊的文檔結構部分,經過動態載入到其父容器中
main_html: ''
+ '<div class="spa-chat">'
+ '<div class="spa-chat-head">'
+ '<div class="spa-chat-head-toggle">+</div>'
+ '<div class="spa-chat-head-title">Chat</div>'
+ '</div>'
+ '<div class="spa-chat-closer">x</div>'
+ '<div class="spa-chat-sizer">'
+ '<div class="spa-chat-msgs"></div>'
+ '<div class="spa-chat-box">'
+ '<input type="text" />'
+ '<div>send</div>'
+ '</div>'
+ '</div>'
+ '</div>',
// 這個映射表,對應配置裏面的變量,從對象名即可知,是用來
// 保存配置是否可設置狀態。true:表示該變量值可以改變,反之不能改動
settable_map: {
slider_open_time : true,
slider_close_time : true,
slider_opened_em : true,
slider_closed_em : true,
slider_opened_title : true,
slider_closed_title : true,
chat_model : true,
people_model : true,
set_chat_anchor : true
},
// 窗體關閉和打開的動畫時間,使用 $.animate 時使用的時間
slider_open_time : 250,
slider_close_time : 250,
slider_opened_em : 18,
slider_closed_em : 2,
// 兩個最小閥值用來防止頁面被縮放的時候。聊天窗體同比例縮放致使變的過小而作出的限制
// 這裏單位是:em
slider_opened_min_em : 10,
window_height_min_em : 20,
// 窗體打開和隱藏狀態時。鼠標放在上面時顯示的提示內容,經過元素的'title'屬性實現
slider_opened_title : 'Click to close',
slider_closed_title : 'Click to open',
// 兩個數據模型,該書採用了數據庫插件:taffyDb 來管理和模擬數據
chat_model : null,
people_model : null,
// 此方法是聊天窗體顯示和隱藏的關鍵
// 核心模塊shell 正是經過這個接口來管理聊天模塊觸發錨的變化從而
// 讓聊天模塊具有前進後臺歷史等瀏覽器功能
// 該方法指向shell模塊中的 setChatAnchor 函數,
// setChatAnchor 在 shell 中定義,與 'uriAnchor' 插件發生聯繫
// 而後經過配置模塊:configModule, 將該函數與`chat`模塊發生聯繫,從而
// 使 chat 改變 -> setChatAnchor -> shell 錨管理
set_chat_anchor : null
},
經過 set_chat_anchor
改變聊天窗體狀態變化路徑圖
經過圖中就能明顯的看出,chat 是怎樣經過 shell 來實現狀態更新。以及實現自身的前進後退歷史等功能
stateMap
相對於基本配置容器裏面的配置,在執行過程當中基本都不會有變化的值來講,stateMap
裏面就是一些執行過程當中,會因爲用戶行爲而發生變化的一些狀態值了
忽然發現人在不一樣的時間和不一樣的認知段會對同一個事物的理解和解釋大有不一樣(廢話麼。誰不知道啊!
!
)
var stateMap = {
// 模塊容器。很少說
$container: null,
// 位置值,表示模塊窗體因用戶行爲而發生變化的狀態值
// 主要有:'closed','opened','hidden'
position_type : 'closed',
// 單位轉換, px/em,實際執行過程當中會涉及到元素的位置設置。經過轉換
// 獲得實際像素值,去設置
px_per_em : 0,
// 下面三個就是針對三個不通狀態時,窗體的位置了
slider_hidden_px : 0,
slider_closed_px : 0,
slider_opened_px : 0
}
針對 stateMap
裏面的屬性,有幾個針對性的函數
第一個就是 setPxSizes
。因爲頁面都是經過 em 來設置大小的,所以在獲取實際像素值的時候需要作個響應的轉換
/* 這裏面幹了下面幾件事: 1. 獲取 em -> px 的單位值,而後計算出當前文檔窗體的總高度值:window_height_em 2. 依據文檔窗體決定模塊窗體打開時的高度:opened_height_em 3. 更新 stateMap 裏面的窗體相關的狀態值 4. 最後肯定聊天窗體內容體的詳細高度 */
setPxSizes = function () {
var
px_per_em, opened_height_em, window_height_em;
px_per_em = getEmSize( jqueryMap.$slider.get(0) );
// 計算窗體高度:em
window_height_em = Math.floor(
( $(window).height() / px_per_em ) + 0.5
);
// 依據範圍值來決定窗體打開的高度
opened_height_em
= window_height_em > configMap.window_height_min_em
? configMap.slider_opened_em
: configMap.slider_opened_min_em;
stateMap.px_per_em = px_per_em;
stateMap.slider_closed_px = configMap.slider_closed_em * px_per_em;
stateMap.slider_opened_px = opened_height_em * px_per_em;
jqueryMap.$sizer.css({
height: ( opened_height_em - 2 ) * px_per_em
});
};
// 這個函數,需要在初始化模塊initModule中將模塊載入到容器中以後,
// 就需要執行,因爲當中涉及的一些狀態值需要在興許執行操做過程當中就要用到,
// 比方:px_per_em, slider_closed_px,slider_opened_px 等等
第二個函數就是:setSliderPosition
,這個是真正改動聊天窗體顯示隱藏狀態的函數,裏面經過$.animate
動畫實現,並且是提供給 shell
模塊。在 hash 值發生變化時觸發了hashchange
事件調用事件處理函數:onHashChange
,裏面依據詳細的狀態值去調用的,所以上面的狀態走向圖還不是很是準確。
/*
這裏面的實現。主要依賴與:position_type,依據用戶行爲,去改變這個值。而後終於經過 hash 值的變化。傳到這裏,去改變窗體顯示或隱藏
裏面涉及到的參數:
height_px:動畫的目標屬性,窗體高度
animate_time: 動畫時間
slider_opened_title:以及窗體改變後顯示的 title 屬性值
最後經過動畫結束後的回調:callback
*/
setSliderPosition = function ( position_type, callback ) {
var
height_px, animate_time, slider_title, toggle_text,
setAttr;
if ( stateMap.position_type === position_type ) {
return true;
}
setAttr = function ( height, an_time, title, text ) {
height_px = height;
animate_time = an_time;
slider_title = title;
toggle_text = text;
};
switch ( position_type ) {
case 'opened':
setAttr(
stateMap.slider_opened_px,
configMap.slider_open_time,
configMap.slider_opened_title,
'='
);
break;
case 'hidden':
setAttr( 0, configMap.slider_open_time, '', '+' );
break;
case 'closed':
setAttr(
stateMap.slider_closed_px,
configMap.slider_close_time,
configMap.slider_closed_title,
'+'
);
break;
default:
return false;
break;
}
// 重置位置類型
stateMap.position_type = '';
jqueryMap.$slider.animate(
{ height: height_px },
animate_time,
function () {
jqueryMap.$toggle.prop( 'title', slider_title );
jqueryMap.$toggle.text( toggle_text );
stateMap.position_type = position_type;
callback && callback( jqueryMap.$slider );
}
);
return true;
};
上面的圖改動以後加入 setSliderPosition
就比較完美了
最後爲了應對窗體的 resize
事件。窗體需要作出對應的變化:handleResize
// spa.chat.js
handleResize = function () {
if ( !jqueryMap.$slider ) { return false; }
setPxSizes();
if ( stateMap.position_type === 'opened' ) {
jqueryMap.$slider.css({ height: stateMap.slider_opened_px });
}
return true;
};
// spa.shell.js 中應對 window 的 resize 事件
onResize = function ( event ) {
if ( stateMap.resize_idto ) { return true; }
spa.chat.handleResize();
stateMap.resize_idto = setTimeout(function () {
stateMap.resize_idto = undefined;
}, configMap.resize_interval);
return true;
};
值得一提的是應對 window
的 resize
事件方案採取的是針對每個模塊實現本身的應對方法。從而使模塊能本身來決定怎樣應對窗體的縮放應對方式
jqueryMap
這裏面的東西就很少記錄了。都是些死的東西,緩存模塊內元素的對象,方便jQuery
使用,相同需要在該模塊被追加到模塊容器shell
中以後才調用
/* 這裏就不能直接用 $.html 了,而是使用 $.append 追加到模塊容器 `shell` 模塊當中 */
setJqueryMap = function () {
var
$append_target = stateMap.$append_target,
$slider = $append_target.find( '.spa-chat' );
jqueryMap = {
$slider : $slider,
$head : $slider.find( '.spa-chat-head' ),
$toggle : $slider.find( '.spa-chat-head-toggle' ),
$title : $slider.find( '.spa-chat-head-title' ),
$sizer : $slider.find( '.spa-chat-sizer' ),
$msgs : $slider.find( '.spa-chat-msgs' ),
$box : $slider.find( '.spa-chat-box' ),
$input : $slider.find( '.spa-chat-box input[type=text]' ),
};
};
這篇主要介紹了該書對 chat
模塊的處理,用這個演示樣例來講明子模塊怎樣和模塊管理器模塊:shell相互做用。怎樣組裝子模塊。怎樣經過錨變化來管理子模塊的狀態變化,以及怎樣應對 window
的 resize
事件的思想。另外還包括了怎樣移除 chat
模塊,當中涉及的 removeSlider
處理等。
這裏面需要注意的地方也沒幾處,主要感受仍是要弄清楚,模塊的狀態值和狀態的變化怎樣在子模塊和 shell
模塊之間是怎樣傳遞以及起做用的,上面兩張過程圖更直觀點。
到此。模塊的頁面和組裝基本完畢了,下一篇將會介紹該書是怎樣實現數據模型,怎樣讓數據模型發生做用(數據管理插件:taffyDb)。
完結,待續……!