Kit作為一個UI庫,我並沒有打算讓大家都來學習我的Kit的Core,背熟我的API,這種跟風的學習方式一點意義都沒有,今天jQuery熱,大家都是學jQ ,明天SeaJs火了,大家都去炒SeaJs,所以我在KitJs裡面,專門為jQ的用戶準備了一個語法糖(Suger.js),完全模擬jQ的API,除了實現,接口都一樣,也方便大家直接拿來主義的改造Kit的組件。當然,作為一個純技術Fan來說,深入理解一門技術是如何實現的,遠比拿來主義更有趣的多^_^。當然了,如果你出於KPI考慮,或者老闆的老闆的專案獎金,直接拿來主義抄襲Kit的組件代碼,完成你的KPI,我也不介意這樣的行為,只要您喝水不忘挖井人,在跟同事吹水的時候,也能宣傳一個KitJs,我就很感激您了。同時,Kit也是一個很年輕的庫,出於不斷的發展之中,有一些BUG以及瀏覽器兼容問題,在所難免,我一個人也精力有限,在這個前端戰火紛飛的年代,歡迎更多志同道合的基友一起把他搞大,共同進步。
同時,今天發布了一個kitjs的對話框元件,demo位址為http://xueduany.github.com/KitJs/KitJs/demo/Dialog/demo.html
(一)Kit目錄格式
言歸正傳,在KitJs裡,kit.js是作為核心的Core檔案的存在,他包含了一些最常用的Dom以及Object,繼承的操作,同級目錄下按照功能的劃分擴展了一批string. js,math.js等等都是為了實現特定方向功能的擴展。每一個獨立的js檔案都包含一個Class的建構器,以及一個全域物件的實例,
以kit.js為例,包含了$Kit類,以及$Kit類的實例$kit(以$開頭是為了避免與常用的變數衝突),
其他各類,都以Link的方式,掛在$Kit,以及$kit實例實例上,如math.js,包含了$Kit.Math類,以及$kit.math實例,這樣保證全局範圍裡只有$Kit和$kit兩個污染。同時,在kit.js,我們定義了一個命名空間叫做$kit.ui,在實體目錄下,以kit.js同等級的Widget目錄,一字排開,多個首字母大寫的目錄
widget目錄下所有目錄都是kitjs的元件目錄,每個獨立js檔案只包含一個獨立元件的class建構器(非實例),同時可以相容commonJs的module模式(可以符合CommonJs的Modules/1.1 規範,以及AMD方式改造,具體改造方式後面會以後會詳細提及)
(二)Kit元件預設程式碼模板,註解符合jsdoc規格
我們以對話框元件舉例,每個元件都類似如下
首先是jsdoc的註釋,@class申明是什麼類,@require xxx.js,申明依賴哪些元件
(三)構造器以及初始化方法
每個類別都是標準的function(config){}的方式定義個建構器,這裡要注意的是,每個kitjs元件的建構器預設預留一個config參數,作為個人化配置的輸入,
同時在類別的建構器,有個靜態成員,defaultConfig對象,用來存放kitjs組件的預設配置
在使用kitjs的元件,首先是需要透過new Instance的方式new $kit.ui.Dialog.YesOrNo,初始化一個新的實例物件出來,這是僅僅是初始化了一個js的元件對象,還沒有HTML ,需要執行init方法,創建HTML,加入doc中,等於給靈魂澆上血肉^_^。
可能有同學會問,為什麼不把init方法直接放在構造器裡面,而要另外單獨放出來?
1是因為在繼承時候需要實例化父類,當子類繼承於父類的時候,會設定子類的prototype對象為父類的new Instance新的實例對象,如果在構造器裡面放了init的初始化方法,會導致父類別的HTML直接執行,產生垃圾程式碼,
2是因為考慮懶載入的情況,需要HTML程式碼在適當的時間執行,而不是一開始初始化時立即執行
所以使用kitjs元件的預設方式是
實例化之後,執行init方法(init方法會傳回目前元件對象,有return程式碼7)
上圖可以發現,在dialog中所有API method都是掛在prototype上,透過原型擴展的方式實現繼承以及傳遞給實例物件
觀察$kit.ui.Dialog.YesOrNo元件的建構子程式碼,
(四)KitJs的繼承
他透過$kit.inherit方法申明了與$kit.ui.Dialog物件的繼承關係,這裡會有同學要問,為什麼要在構造器裡面繼承,而不是直接寫在外面?
原因是:
1.kitjs是一個基於prototype維繫繼承關係的
2.要使用kitjs的元件,必須要實例化該元件對象,每個元件都是透過new Instance的方式,透過建構器建立的
所以我把繼承關係的執行放在程式碼的建構器中,這樣在實例化一個新的元件時,就會順著目前元件的建構器的繼承方法,逐級去繼承到他父類別的成員以及方法。
當子類別需要修改父類別的方法時,只需要在子類別的prototype裡從定義一個同名的method即可覆寫父類別的繼承方法。
在命名上,kitjs遵循,子類別延續父類別的類別名稱作為Namespace,一直連結下去,如上圖的$kit.ui.Dialog,$kit.ui.Dialog.YesOrNo
kitjs的繼承實作也很簡單
實例化一個父類對象,將父類的實例所有成員copy到子類的原型上,然後重置子類的原型的構造器為子類構造器,再給子類構造器掛一個link ,指向父類,透過$kit.inherit方法,在子類別$kit.ui.Dialog.YesOrNo實例化的過程中,就可以繼承父類$kit.ui.Dialog的所有子類別不存在的成員,實現類似靜態語言的繼承
(五)config參數,HTML與Css的耦合拆解/換膚?
kit的元件構造器習慣傳入一個 Map類型的參數,從來個性化元件,在kit元件初始化的時候,會自動用使用者提交的config參數覆寫預設的defaultConfig後開始初始化。
對任何一個元件來說,擺脫不了是HTML結構的變化,以及Css樣式的改變
kit把這種耦合分解在config的參數配置裡面,
首先使用HTML模板技術,kit提倡使用$kit.newHTML方法直接根絕HTML String,產生HTML DOM插入文件流,
所以我們抽取元件的大概HTML內容,封裝成HTML String模板,存放在元件的defaultConfig裡面,如果使用者需要修改HTML模板,自己在初始化的時候使用自訂的config,覆蓋預設的defaultConfig裡面的模板字段即可,
在HTML模板與Css的耦合分解上,kit用了一個技巧就是把className用js模板的方式,分解開來
透過在init方法中的$kit.tpl 將config 中的html以${xxx}的方式對應config中的xxx做替換
同時所有的樣式都在css裡面設置,
如果有多套皮膚需要切換,可以選擇在初始化時候,透過config指定${cls}對應的實際className來達到修改模板的className,來達到換膚的效果。
(六)小結
基本上,透過對$kit.ui.Dialog.YesOrNo元件的程式碼分析,我們對kitjs的元件實作結構有了一個大致的了解。其實設計一個頁面元件並不難,但是設計一個能適應各種要求,在各種場合下,可以很快速的變形,並且適應開發,是一個很難的要求。 kit透過對HTML模板以及Css的拆分,自訂config參數與defaultConfig的配合,子類別透過繼承的方式獲得父類別的屬性以及方法,同時根據不同的業務需求重構相關程式碼,基本上可以靈活的滿足各種層次,各種環境下的業務UI元件需求。
KitJs包含了基本函式庫和UI函式庫,
基本函式庫: 選擇器功能,dom操作功能,動畫功能,增強dom事件,增加hashtree資料結構,io功能,本機儲存功能,多執行緒,range等等
還有一個模擬jquery操作格式的suger.js
UI庫包含了:增強的form元素,彈出層,媒體播放器,驗證框架,瀑布流,聯動,幻燈片,日曆,上傳組件,模板引擎等等