JS控件的生命周期介紹
JS控件的生命周期跟其他平臺(tái)UI的生命周期類似,但是又有自己的特點(diǎn),我們只有將控件的生命周期劃分清晰,所有的控件編寫、mixins的編寫和plugin的編寫才能遵循控件的生命周期做統(tǒng)一的管理。在這里我把JS的生命周期定義為4部分:
1.initializer: 初始化,做一些不牽扯DOM操作的初始化操作
2.createDom: 創(chuàng)建 DOM,在這個(gè)過(guò)程中我們創(chuàng)建控件需要的DOM結(jié)構(gòu)
3.renderUI: 生成控件的內(nèi)部元素,在這里調(diào)用子控件的渲染方法,開(kāi)啟子控件的生命周期
4.bindUI: 綁定事件,可以綁定子控件事件也可以綁定內(nèi)部DOM的事件
5.synUI: DOM結(jié)構(gòu)以及子控件生成完畢后,我們?cè)谂渲庙?xiàng)中傳入的值或者默認(rèn)的配置項(xiàng)要應(yīng)用到DOM上,例如 width,height,focusable之類的屬性
6.destructor: 析構(gòu)函數(shù),移除控件,清理控件上的事件,清理子控件,清理控件自己的DOM以及控件的一些對(duì)其他控件的引用。

圖 1
初始化:
控件初始化過(guò)程中做以下事情:
1.調(diào)用繼承的父類的初始化函數(shù),包括原型鏈上的父類和mixins
2.處理配置項(xiàng),合并默認(rèn)配置項(xiàng)和用戶傳入的配置項(xiàng)
3.處理綁定到改對(duì)象的事件
4.初始化插件(plugin)
初始化完成后,是否創(chuàng)建DOM看具體的策略,類似于ext的實(shí)現(xiàn),可以延遲創(chuàng)建DOM
創(chuàng)建DOM
創(chuàng)建DOM的過(guò)程如下:
1.調(diào)用繼承的父類的創(chuàng)建DOM的函數(shù),包括原型鏈上的父類和mixins
2.創(chuàng)建控件的DOM
3.調(diào)用控件插件的創(chuàng)建DOM的函數(shù)
渲染子控件和內(nèi)部DOM操作
執(zhí)行過(guò)程如下:
1.調(diào)用父類的渲染函數(shù),包括原型鏈上的父類和mixins
2.調(diào)用插件的渲染函數(shù)
我們可以在頂級(jí)的父類來(lái)初始化子控件。好處是,子類不需要做子控件初始化的操作此時(shí):
1.如果子控件還未初始化則執(zhí)行初始化
2.繼續(xù)執(zhí)行子控件的創(chuàng)建DOM、渲染子控件、綁定事件、同步配置項(xiàng)函數(shù)執(zhí)行
綁定事件
由于此時(shí)控件的DOM和內(nèi)部的子控件已經(jīng)渲染完畢,則可以在子控件或者DOM上綁定事件。綁定事件的過(guò)程:
1.調(diào)用父類的綁定事件方法,包括原型鏈上的父類和mixins
2.調(diào)用插件(plugin)的綁定事件方式
注意:在子控件或者內(nèi)部DOM上綁定事件時(shí),使用委托,不要直接在子控件或者DOM上綁定事件,一旦子控件添加或者刪除,內(nèi)部DOM變化都會(huì)引起事件失效。
同步配置項(xiàng)
首先說(shuō)明一下什么叫做同步配置項(xiàng),前面我們?cè)诔跏蓟丶r(shí),已經(jīng)對(duì)配置項(xiàng)做過(guò)一定的處理(至于如何處理,后面講 JS控件屬性 的時(shí)候會(huì)講到),但是配置項(xiàng)并未作用到DOM上或者內(nèi)部子控件上。
為什么在這時(shí)候處理同步,而不是在創(chuàng)建DOM和渲染子控件時(shí),有2個(gè)原因:
1.在創(chuàng)建DOM和渲染子控件時(shí),所有的DOM和子控件并未完整生成此時(shí)同步需要進(jìn)行大量判斷
2.我們需要把同步配置項(xiàng)的工作提取成方法,修改配置項(xiàng)時(shí),內(nèi)部DOM和子控件跟著變化。
例如:配置項(xiàng)里有 { width : 100 }
1.如果我們?cè)阡秩綝OM時(shí)同步,則可能把“width=100px;”直接設(shè)置到DOM上,而到我們需要修改這個(gè)width時(shí),我們還需要寫一個(gè)函數(shù)來(lái)設(shè)置這個(gè)值。
2.反之,我們把同步配置項(xiàng)集中處理,將一個(gè)個(gè)的同步配置項(xiàng)的過(guò)程抽取成一個(gè)個(gè)函數(shù),那么我們初始化 width的過(guò)程和修改width的過(guò)程完全一樣,這樣概念和邏輯就統(tǒng)一起來(lái)。
同步配置項(xiàng)的過(guò)程依然如其他步驟一樣:
1.調(diào)用父類的同步方法,包括原型鏈上的父類和mixins
2.調(diào)用插件(plugin)的同步方法
注意:我們應(yīng)該可以配置一個(gè)配置項(xiàng)是否在此時(shí)同步,原因有很多,比如多個(gè)配置項(xiàng)會(huì)產(chǎn)生同一操作,如果多個(gè)配置項(xiàng)同時(shí)同步,那么一個(gè)過(guò)程會(huì)反復(fù)執(zhí)行多次。
移除控件
任何對(duì)象都有構(gòu)造函數(shù),必定也有析構(gòu)函數(shù),但是這個(gè)函數(shù)往往是大家最容易忽視的地方,但是也是非常重要的地方,暫且不說(shuō)內(nèi)存泄露之類的問(wèn)題,就是如果一個(gè)控件的移除工作做得不夠好,會(huì)對(duì)正常的使用帶來(lái)很大的麻煩。
這個(gè)函數(shù)又是最不好寫的一個(gè)函數(shù),因?yàn)樗枰幚硪韵鹿ぷ鳎?
1.清理使用的其他控件,是否也移除看具體情形。區(qū)分 關(guān)聯(lián)和聚合
2.清理子控件
3.清理綁定到控件和DOM上的事件
4.移除DOM
5.清理變量的引用,這個(gè)比較麻煩和繁瑣,所以我們需要對(duì)控件的引用做統(tǒng)一的管理
同樣此函數(shù)也要執(zhí)行:
1.調(diào)用父類的析構(gòu)函數(shù),包括原型鏈上的父類和mixins
2.調(diào)用插件的析構(gòu)函數(shù)
問(wèn)題
上面講的全部是具體的步驟,但是在實(shí)現(xiàn)的時(shí)候遇到了一系列的問(wèn)題:
1.調(diào)用父類的方法存在問(wèn)題
1)調(diào)用原型鏈上的父類方法,只能使用 className.superclass.method.call(this)這類的方法,this.constructor.superclass.method.call(this)不能使用,原因在 js 控件繼承 的extend一章中有講到,這種調(diào)用方式繁瑣而且維護(hù)不方便。
2)調(diào)用mixins上的方法,在JS 繼承 mixins一章中我講到過(guò)mixins的實(shí)現(xiàn)原理,覆蓋同名方法,mixins的方法其實(shí)已經(jīng)作為控件的prototype上的方法,所以最好不要使用同名方法,如果多個(gè)mixins都是用 renderUI,synUI之類的方法,而繼承這些mixins的控件沒(méi)有實(shí)現(xiàn)renderUI這類方法,那么就會(huì)被覆蓋。
2.調(diào)用插件的方法也存在問(wèn)題
1)我們需要獲得當(dāng)前控件的引用
解決方式:
1. 針對(duì)調(diào)用父類的方法我們可以在控件渲染時(shí),按照原型鏈的順序,先調(diào)用父類的方法再調(diào)用子類的方法直到當(dāng)前控件:
如上面的繼承關(guān)系,我們執(zhí)行C.renderUI()時(shí),按照繼承原型鏈的頂層向下執(zhí)行。
2. 執(zhí)行minxins的方法,我們執(zhí)行renderUI時(shí),去依次執(zhí)行 mixin 的__renderUI方法。
3. 執(zhí)行父類的renderUI 時(shí),如果也存在mixins那么執(zhí)行mixin的 __renderUI方法。

圖3
如上圖所示: inherits表示原型鏈繼承,extends表示 mixin擴(kuò)展
那么c.renderUI的執(zhí)行過(guò)程如下:
A.renderUI ->D.__renderUI->B.renderUI->E.__renderUI->C.renderUI
3. 調(diào)用插件方法時(shí)需要傳遞控件本身的引用即可,如:
plugin1.render(this)
4. 析構(gòu)函數(shù) destructor比較特使,執(zhí)行的順序跟上面2中講的順序有所不同:
子類 destructor -> 子類擴(kuò)展 destructor -> 父類 destructor -> 父類擴(kuò)展 destructor
按照?qǐng)D3的繼承結(jié)構(gòu)其析構(gòu)函數(shù)執(zhí)行的順序是:
C. destructor ->E.__destructor->B.destructor->E.__destructor->a.destructor
原因是,子類的一些引用依賴于父類或者擴(kuò)展類,如果父類和擴(kuò)展類先執(zhí)行析構(gòu)函數(shù),那么子類在使用某些變量/屬性時(shí)會(huì)報(bào)錯(cuò)。 
這一節(jié)我把控件的生命周期講了一遍,所有的著一些都是來(lái)自于 KISSY框架的UIBase,感興趣的可以去看一下,非常精彩的實(shí)現(xiàn)http://docs.kissyui.com/kissy/docs/#!/api/KISSY.Component.UIBase的
相關(guān)文章
js實(shí)現(xiàn)單層數(shù)組轉(zhuǎn)多層樹(shù)
這篇文章主要介紹了js實(shí)現(xiàn)單層數(shù)組轉(zhuǎn)多層樹(shù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06
JS實(shí)現(xiàn)獲取鍵盤按下的按鍵并顯示在頁(yè)面上的方法
這篇文章主要介紹了JS實(shí)現(xiàn)獲取鍵盤按下的按鍵并顯示在頁(yè)面上的方法,涉及JavaScript針對(duì)鍵盤事件及頁(yè)面元素的相關(guān)操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11
JS實(shí)現(xiàn)雙擊屏幕滾動(dòng)效果代碼
這篇文章主要介紹了JS實(shí)現(xiàn)雙擊屏幕滾動(dòng)效果代碼,涉及JavaScript鼠標(biāo)事件的響應(yīng)及頁(yè)面元素屬性的動(dòng)態(tài)變換技巧,需要的朋友可以參考下2015-10-10
JavaScript中具名函數(shù)的多種調(diào)用方式總結(jié)
這篇文章主要介紹了JavaScript中具名函數(shù)的多種調(diào)用方式總結(jié),本文總結(jié)了4種方法,需要的朋友可以參考下2014-11-11
JS實(shí)現(xiàn)簡(jiǎn)單的選擇題測(cè)評(píng)系統(tǒng)代碼思路詳解(demo)
本文給大家分享js實(shí)現(xiàn)簡(jiǎn)單的選擇題測(cè)評(píng)系統(tǒng)實(shí)例代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧2017-09-09

