YUI 3 元件架構

此篇文章最近更新時間為2009-08-10 05:46:54 目前共有4篇留言

關於作者 - JosephJ

任職於 Faria。喜好戶外運動、2008 年 5 月完成「跑步環島」。對於新技術跟程式碼有著強烈的偏執狂。

公司有些系統是 extends YUI 3 的 Component Infrastructure,一直看不是很懂,所以花了些時間研究一下此元件架構。

為什麼要有元件架構

YUI 在 2.x 常被人詬病的一點就是檔案太大。例如 Connection Manager 除了基本的 AJAX、尚包括了表單處理、利用 Iframe 達成的不換頁上傳功能,所有功能都包裝在一個 JavaScript 檔案中(原始檔案 12KB、GZip 3KB),但開發者所需的可能只是佔原始碼 20% 的基本 AJAX 功能,實在是非常浪費。

而在 YUI 3.x 將功能拆散,開發者可依需求指定。例如 IO(Connection Manager 在 3.x 的新名稱)開發者若只需要基本的 XHR 功能,只要用使用 io-base 單一模組(原始檔案 4KB、GZip 小於 1 KB)即可 ; 而進階功能也有不同的模組,io-xdr 負責跨網域存取(原始檔案 848B、GZip 567B)、io-form 負責表單 AJAX Post、io-upload-iframe 負責檔案上傳、io-queue 負責工作排程,開發者便可自行選擇所需功能、達成檔案最小化的目的。但若開發者不希望了解複雜性也不在乎效能時,他可以使用包含所有功能的 io。

// 最基本的 AJAX 功能:
YUI().use('io-base', function (Y) {
    // do something here
});
// 要用到跨網域跟工作排程(不需要指定 io-base,程式會自動幫你判斷抓入):
YUI().use('io-xdr', 'io-queue' function (Y) {
    // do something here
});
// 使用全部功能
YUI().use('io' function (Y) {
    // do something here    
});

什麼是元件架構?

而 YUI 元件架構(YUI's AOP Infrastructure)就是讓 YUI 3.x 可功能模組化的基礎。藉由此架構,開發者或 YUI 官方可以有效率地建立 JavaScript 物件導向的元件及自訂全新的 YUI 控制項,甚至以非侵入式的作法改變 YUI 的 Class 與 Instance

yui-component
  • Attribute 提供物件導向中屬性的封裝。
  • Base 繼承了 Attribute,是建立一個功能(Utility)的基礎。
  • Plugin 繼承 Base,替一個已建立物件(Instance)增加新功能。
  • Extension 繼承 Base,修改一個元件(Class)的功能。
  • Widget 繼承 Base,是建立一個有介面控制項(Widget)的基礎。

所以在設計物件 Class 時只需規劃核心,做出有基本功能的 Utility 或 Widget,然後再用 Plugin 或 Extension 來增加新功能。例如前面提到的 io-form, io-upload-iframe 便是利用 Extension 達成、而 YUI 2.x 的 Menu 控制項在 YUI 3.x 不再是個 Widget,只是一個 Node Utility 的 Plugin。

Attribute

官方文件:http://developer.yahoo.com/yui/3/attribute/

一般基本 JavaScript Class 的屬性都是 public 可隨意修改的,控管不易會有衍生許多問題。用了 Attribute 便可以封裝 Class 中的屬性必須要用 set 或 get 的方式才能存取與修改屬性,也可指定屬性有 readOnly、validator、writeOnce 等特殊權限。

其實 YUI 2.x 的 Element Utility 及 DataSource 都有提供屬性封裝的功能、但 Attribute 在 YUI 3.x 統一了其差異並增加特殊權限的數量,另外屬性改變可利用 on 與 after 等方法來做監聽。

YUI().use('attribute', function(Y) {
    function Car(attrs) {
        // 將參數 (attr) 寫入設定好的屬性 (Car.attr) 中
        this.addAttrs(Car.attr, attrs); 
    }
    // 將 Y.Attribute 的  Public Method 拿到用 Car 用
    Y.augment(Car, Y.Attribute); 
    // 設定此物件的可用屬性
    Car.attr = {
        year : { // 出廠年份
            value : 1995,  // 預設值
            validator : function(val) { // 檢查是否為數字,不然就會無法設定
                return Y.Lang.isNumber(val); 
           }             
       }, 
       brand : {
           default : 'civic'
       }
    };
    var oCar = new Car({year:2009});
    oCar.set('brand', 'ford');
});
Attribute 的使用範例

Base

官方文件:http://developer.yahoo.com/yui/3/base/

建立一個基礎 Class 的樣板,已繼承 Attribute。在繼承之前需替本來的 Constructor 建構式另外再加上 NAME 跟 ATTR 兩個 Static Properties。

YUI().use("base", function(Y) {
    function Car(config) {
        // 呼叫 Y.Base 的 Constructor 並將參數帶入    
        Car.superclass.constructor.apply(this, arguments);
    }
    // Required,用來辨認使用到此 Class 的 Prefix
    Car.NAME = 'car';
    // Required,定義此 Class 有哪些屬性
    Car.ATTRS = { 
        year : {}, 
        brand : {}
    };
    // 繼承 Y.Base    
    Y.extend(Car, Y.Base, {
        // 在這裡定義 Car 有哪些 Public Methods
    });
});
Base 的使用範例

Plugin

官方文件:http://developer.yahoo.com/yui/3/plugin/index.html

元件在實作出來後,勢必是沒有辦法滿足每個人的需求。為了達成其他的人目的,使用者可能會試圖了解原本 Class 的結構做修改,不然就是跟作者發需求等待樹個月、甚至作者還會為了不同需求有不同版本的 Class,都是很不合裡的事情。

Plugin 可針對以 Base/Widget 為基礎所產生的 Instance 增加功能。作者不再需要為了讓一個 Class 要有很多的功能而變成一個有數千行的檔案,而可以把部分的功能切到 Plugins 中做漸進式支援、甚至讓使用此元件的人自己去做 Plugin、進而分享給其他有相同需求的人!Plugin 的好處是你可以在 Instance 產生後的任何時間點 plug、或 unplug 來增加或移除功能

Extension

Extension 的作用與 Plugin 幾乎一樣,都是用來包裝某些特定功能、不讓 Class 無限膨脹。 但兩者間最大的不同就是 Extension 是發生在 Class Level ,而 Plugin 則是用在 Instance Level 的

Widget

用來建立 YUI 3 Widget(有介面的控制項)的基礎元件。Base 有的 Widget 都有,除了基本的 init、destroy 方法外,Widget 還多了 render 方法。由於是用於建立使用者 UI,所以 Widget 考慮了許多面向的事情,像是 Class 的結構是可以被繼承的、也把使用者互動的設計放入。

  • 基本屬性:所有的 Widget Class 都有以下的預設屬性:boundingBox(最外層)、contentBox(實際上的外觀)、tabIndex(tab 順序)、focused(目前是否被 focus)、width、height、visible、disabled。
  • 加上了 Render 在元件的 Lifecycle 中:Render 方法被定義為 DOM 的處理,也就是 UI 的產生。藉由這樣的觀念開發者可分開程式的核心邏輯的處理 (init, destroy) 與介面的產生 (render)
  • 內定的 Rendering 方法:包含了 renderUI()、bindUI() 與 syncUI() 等方法待開發者實作。
  • 標準漸進式支援
  • 支援語系的 Localization 屬性

結論

整體看來概念是很棒的,以元件架構分散 Class 的複雜度,藉由此方式才能讓 YUI 的每個元件功能不停地擴張下去而不會造成效能問題。但稍微仔細看 Plugin 的作法(Overlay Anim Plugin),會發現使用起來不是那麼的直覺。而且感覺 Documentation 的親和力也較過去 2.x 版來的弱了一些。另外對於區隔 Plugin 與 Extension 的使用時機還不了解。明天有時間的話要來實作個小東西測試一下。



前一篇:推薦:沖繩手環達人 後一篇:@coscup2009

Comments

  1. Oscar 2010-11-24 13:43:52
    好文我頂!
  2. 裕波 2009-12-30 23:44:30
    我是从克军的博客过来的。

    真是好文呀,yui的中文文档实在太少了,如果可以的话,我希望可以将你的博客转换成简体中文,转载到我的博客中去。

    webchina110.cn
  3. 湯姆 2009-10-19 12:16:18
    plugin裡面的文件真的不事很清楚。要多看幾個sample code才可以了解秘技
  4. Jaric 2009-08-14 00:03:46
    阿嗚學長好棒!
暱稱: 必填。
Email: 非必填。若填寫為不公開欄位,僅供站長參考聯繫。
內容: 必填。限 255 個字元以內。
驗證碼:
送出

Facebook Comment