插件讓你可以無侵入地為宿主對象(host object)添加功能。宿主衍生自Base類。node、widget等對象都是宿主對象。我們可以繼承Plugin.Base類建立插件類。但是這也不是必須的,可以通過其他方法建立插件類。
插件類用來向元件執行個體中添加小塊功/特性,不需要将這些功能/特性整合進元件類中,元件類甚至可以完全對這些功能特性一無所知。這樣,我們就可以在元件執行個體層級使用這些功能/特性,避免為實作某些功能特性而把而元件類建構得很大,或者為了實作不同的功能組合建構多個不同的元件類。
引入YUI種子檔案和配置YUI執行個體就不累述了,詳見 YUI 3: YUI 全局對象。
建立插件
以下内容是關于如何建立和使用插件類的,包含如下部分:
- 簡單的插件
- 複雜的插件
- 擴充Plugin.Base類
- 插件監聽器
簡單的插件
對于簡單的插件類,如果它們沒有自己的事件和屬性,不通過監聽宿主對象的事件來修改宿主對象的預設行為,不重寫宿主對象的方法的話,插件類可以隻是簡單的原生javascript類。
插件類唯一必須的是一個用作名字空間的靜态屬性“NS”。該靜态屬性的值用作從宿主執行個體上通路插件執行個體。也就是說,一旦插件被 “插到”宿主執行個體上後,可以通過hostObj.namespace得到plugin執行個體的引用。
當插件被“插到”一個宿主執行個體上後,插件的執行個體被建立,一個對宿主執行個體的引用被添加到傳入插件構造器的配置對象上。這樣,插件執行個體可以引用宿主執行個體。(當一個插件被從宿主執行個體上“拔出”後,該插件執行個體被銷毀。)
以下是一個簡單的插件類:
//這個AnchorPlugin插件被設計成Node執行個體的插件 (宿主是Node執行個體)
function AnchorPlugin(config) {
// 存放宿主執行個體(Node執行個體)的引用,以便插件的方法使用。
this._node = config.host;
}
// 被-插入Node執行個體後,在Node執行個體的"anchors"屬性上能通路到插件
AnchorPlugin.NS = "anchors"
AnchorPlugin.prototype = {
disable: function() {
var node = this._node;
var anchors = node.queryAll("a");
anchors.addClass("disabled");
anchors.setAttribute("disabled", true);
}
};
下面代碼展示在Node對象上插入“AnchorPlugin”插件:
var container = Y.one("div.actions");
container.plug(AnchorPlugin);
通過NS屬性的值,可以在Node執行個體上通路到插件執行個體:
container.anchor.disable();
進階插件類
上述的簡單插件類能滿足簡單功能/特性。但是,當你想在插件類中封裝更複雜的功能/特性時,對attributes和events的支援就派上用場了。對于許多插件而言,你将需要改變宿主執行個體的預設行為(比如:一個Animation 插件可能需要改變widget類的預設show/hide行為)。
對于這樣功能複雜的插件,你應該通過擴充Plugin.Base類來建構它。
插件類是Base的子類,是以,它也支援attribute、生命周期方法、自定義事件。另外,我們還可以在插件類中監聽響應宿主執行個體觸發的事件,或者在宿主執行個體某方法執行之前,注入插件自定義的邏輯代碼(基于YUI3的AOP基礎結構)。Plugin.Base類還在它的“host”屬性中存放對宿主執行個體的引用,可以在插件實作中通過this.get(“host”)通路到宿主執行個體。
擴充Plugin.Base
你可以像擴充Base類一樣擴充Plugin.Base類。需要注意的是擴充Plugin.Base類時,宿主執行個體被自動設定為插件類的“host”屬性的值。而在簡單的插件類中需要手動地通過構造器的配置對象把宿主執行個體設定成插件類的屬性值,這樣才能在插件類中通路到宿主執行個體。
進階插件類的結構和其他擴充自Base類的類是一樣的。隻是多了一個NS靜态屬性。 (see the Basedocumentation for details about NAME and ATTRS).
// A plugin class designed to animate Widget's show and hide methods.
function WidgetAnimPlugin(config) {
WidgetAnimPlugin.superclass.constructor.apply(this, arguments);
}
// Define Static properties NAME (to identify the class) and NS (to identify the namespace)
WidgetAnimPlugin.NAME = 'widgetAnimPlugin';
WidgetAnimPlugin.NS = 'fx';
// Attribute definitions for the plugin
WidgetAnimPlugin.ATTRS = {
animHidden : {
...
},
animVisible: {
...
}
};
// Extend Plugin.Base
Y.extend(WidgetAnimPlugin, Y.Plugin.Base, {
// Add any required prototype methods
});
Plugin的監聽器
擴充Plugin.Base類最大的好處就是可以通過Plugin.Base類提供的onHostEvent和afterHostEvent方法來監聽宿主執行個體觸發的事件,還可以通過beforeHostMethod和afterHostMethod方法來改變宿主執行個體的方法。
通過以上由Plugin.Base類提供的方法來改變宿主執行個體的預設方法,而不是通過修改宿主類來改變宿主執行個體的預設方法的好處是:通過“插入”方式做了修改的方法在“拔出”以後,會被還原。這很重要,插件被從宿主執行個體身上“拔出”後,應該被完全地銷毀。
事件
正如上述所說,衍生自Plugin.Base類的插件類,可以監聽并響應宿主執行個體觸發的事件。
比如,當wideget被渲染的時候,他們都會觸發“render”事件。你的插件類可能需要知道這個“render”事件是什麼時候發生的,這樣它才可以在宿主執行個體渲染的HTML代碼中插入一些自定義的HTML代碼。可以使用afterHostEvent方法實作:
// 一個插件類,設計成将widget的show/hide方法改成動畫。
function WidgetAnimPlugin(config) {
//...
}
WidgetAnimPlugin.NAME = 'widgetAnimPlugin';
WidgetAnimPlugin.NS = 'fx';
WidgetAnimPlugin.ATTRS = {
animHidden : {
//...
},
animVisible: {
//...
}
};
// 擴充Plugin.Base,重載預設方法_uiSetVisible。該方法原被用作改變顯示狀态。
Y.extend(WidgetAnimPlugin, Y.Plugin.Base, {
initializer : function(config) {
// 用自定義動畫方法重載Widget的_uiSetVisible方法。
this.beforeHostMethod("_uiSetVisible", this._uiAnimSetVisible);
},
_uiAnimSetVisible : function(show) {
// hide/show.用為插件配置好的動畫執行個體,把show/hide方法改成動畫,替換原來改變顯示狀态的方式。
if (this.get("host").get("rendered")) {
if (show) {
this.get("animHidden").stop();
this.get("animVisible").run();
} else {
this.get("animVisible").stop();
this.get("animHidden").run();
}
// 阻止預設方法執行。
return new Y.Do.Prevent();
}
}
});