使用 jQuery UI Widget Factory 编写有状态的插件(Stateful Plugins)
使用 jQuery UI Widget Factory 編寫有狀態的插件(Stateful Plugins)
使用 jQuery UI Widget Factory 編寫有狀態的插件(Stateful Plugins)
Note
這一章節的內容是基于 Scott Gonzalez 一篇博客?Building Stateful jQuery Plugins(已獲作者許可)
雖然大多數的 jQuery 插件都是無狀態的(stateless),也就是說, 與插件進行交互的就限于調用插件時的那一組對象, 但是有好大一部分功能需求沒辦法通過這種簡單的插件模式來實現。
為了填補這一空白,jQuery UI 實現一套更加先進的插件系統。 它可以管理狀態,允許通過一個插件暴露多個函數,并提供多個擴展點。 這套系統被稱為 widget factory,對應?jQuery.widget, 也是 jQuery UI 1.8 的一部分。不過,它是可以獨立于 jQuery UI 使用的。
我們接下來創建一個簡單的進度條插件,用來演示 widget factory 的能力。
我們首先創建一個只能設置一次的進度條。 下面是實現代碼,使用?jQuery.widget?創建一個插件。 它接受兩個參數,插件名字和帶有具體實現方法的對象。 當插件被調用時,它會創建一個新的插件實例,而插件方法的執行對象也就是那個實例。 這與標準 jQuery 插件實現有兩點是很不一樣的。一是,執行者是對象而不是 DOM 元素; 二是,執行者永遠是單個對象,而不是元素集。
Example?8.3.?用 jQuery UI widget factory 創建一個簡單的有狀態的插件
$.widget("nmk.progressbar", {_create: function() {var progress = this.options.value + "%";this.element.addClass("progressbar").text(progress);} });插件名字必須包含一個命名空間,這里我們用了?nmk?這個命名空間。 但這個命名空間有個限制——只允許一層,也就是說,我們不能使用像?nmk.foo?這樣的命名空間。另外可以看到 widget factory 給我們提供了兩個屬性。一是?this.element, 它指向一個只包含一個元素的 jQuery 對象,如果插件是由包含多個元素的 jQuery 對象調用時,會給其中的每一個元素都分配一個插件實例, 并讓this.element?指向它;二是?this.options, 是包含鍵值對形式的插件參數的 hash 對象,插件的參數就是像這樣傳遞進來的。
Note
本例中使用了?nmk?作為命名空間。 命名空間?ui?則是保留給官方 jQuery UI 插件的。 創建自己的插件的時候,應該使用自有的命名空間的, 這樣可以讓人一看就清楚這插件哪來的,是否是一個大體系的一部分。
Example?8.4.?給 widget 傳遞參數
$("<div></div>").appendTo( "body" ).progressbar({ value: 20 });當我們調用?jQuery.widget?時,與創建標準插件的方式一樣, 它也是通過往?jQuery.fn?上面添加方法的方式來擴展 jQuery 對象。 而那個方法的名稱就是我們定義的插件名稱除去命名空間的部分,案例中是?jQuery.fn.progressbar。調用時所傳遞的參數會傳遞給插件實例的this.options。在下面的代碼中,我們可以在參數中設置一些默認值。 在設計 API 的時候,你應該先搞清楚最通常的用例,并據此設定相應的默認參數, 那么這些參數就成為可選項了。
Example?8.5.?給 widget 設置默認值
$.widget("nmk.progressbar", {// default optionsoptions: {value: 0},_create: function() {var progress = this.options.value + "%";this.element.addClass( "progressbar" ).text( progress );} });給 widget 添加方法
接下來就要初始化進度條了。我們使它可以通過調用插件實例方法的方式來執行一些操作。 要給插件定義方法,只需要將其實現代碼放在定義體內即可。 我們也可以通過在方法名前加下劃線的方式來定義“私有”方法。
Example?8.6.?創建 widget 的方法
$.widget("nmk.progressbar", {options: {value: 0},_create: function() {var progress = this.options.value + "%";this.element.addClass("progressbar").text(progress);},// create a public methodvalue: function(value) {// no value passed, act as a getterif (value === undefined) {return this.options.value;// value passed, act as a setter} else {this.options.value = this._constrain(value);var progress = this.options.value + "%";this.element.text(progress);}},// create a private method_constrain: function(value) {if (value > 100) {value = 100;}if (value < 0) {value = 0;}return value;} });將方法名作為參數傳進去即可調用插件實例的方法。 如果調用的方法需要傳遞參數,只需要將那些參數作為后續參數一同傳遞。
Example?8.7.?調用插件實例的方法
var bar = $("<div></div>").appendTo("body").progressbar({ value: 20 });// get the current value alert(bar.progressbar("value"));// update the value bar.progressbar("value", 50);// get the current value again alert(bar.progressbar("value"));Note
初始化用所用的 jQuery 方法,向它傳遞方法名就可以執行方法,這看起來似乎很奇怪。 但這樣可以在維持原來的鏈式調用的方式的同時,防止 jQuery 命名空間被污染。
Widget 的參數處理
有一個方法?option,是自動生成的。它可以實現在初始化過后, 對參數進行查詢或設置,就像 css,attr 的用法那樣,只傳名字時是查詢, 名字和值都有時是做設置,如果是包含鍵值對的 hash 對象則進行多項設置。 進行查詢時,插件會返回當前該參數的值。 做設置時,插件的?_setOption?方法會被調用,修改多少個就調用多少次。 我們可以自己實現?_setOption?方法來響應這些參數的修改。
Example?8.8.?當參數被修改時執行一些操作
$.widget("nmk.progressbar", {options: {value: 0},_create: function() {this.element.addClass("progressbar");this._update();},_setOption: function(key, value) {this.options[key] = value;this._update();},_update: function() {var progress = this.options.value + "%";this.element.text(progress);} });添加回調功能
擴展插件的一個最簡單的辦法就是添加回調功能, 這樣使用者就可以根據插件狀態的改變來采取行動。下面,我們來嘗試添加一個回調功能, 在進度達到 100% 時觸發。_trigger?方法介紹三個參數: 回調名稱,觸發回調的本地事件對象以及相關的數據。雖然其中只有回調名稱是必須的, 不過其它參數對使用者來說挺有用的。比如說,創建一個可拖拽插件, 我們可以在觸發回調時將原生的 mouseover 事件對象傳遞過去, 用戶在回調函數里就可以根據這個對象中的 x/y 坐標對拖拽進行一些處理。
Example?8.9.?提供回調功能讓用戶進行擴展
$.widget("nmk.progressbar", {options: {value: 0},_create: function() {this.element.addClass("progressbar");this._update();},_setOption: function(key, value) {this.options[key] = value;this._update();},_update: function() {var progress = this.options.value + "%";this.element.text(progress);if (this.options.value == 100) {this._trigger("complete", null, { value: 100 });}} });回調函數實際上只是另外一種參數,因此你也可以像其它參數一樣進行查詢和修改了。 無論回調函數是否設置,事件都會觸發的。事件類型則是由插件名稱和回調名稱合并而成。 回調和事件被觸發時會收到同樣的兩個參數:事件對象和相關數據。可以看下面的例子。
如果你的插件提供些功能是允許用戶阻止操作的,最好的方式就是提供一個可撤銷的回調。 用戶可以像撤銷原生事件那樣,調用?event.preventDefault()?或者?return false,去撤銷回調和相關的事件。如果用戶撤銷了回調,_trigger?方法會返回 false, 在插件中就可以據此采取相應的動作。
Example?8.10.?綁定 widget 事件
var bar = $("<div></div>").appendTo("body").progressbar({complete: function(event, data) {alert( "Callbacks are great!" );}}).bind("progressbarcomplete", function(event, data) {alert("Events bubble and support many handlers for extreme flexibility.");alert("The progress bar value is " + data.value);});bar.progressbar("option", "value", 100);Widget Factory 背后的機制
jQuery.widget?被調用時,它會為你的插件創建一個構造函數, 并以插件定義體作為其 prototype。所有默認提供的方法來自于一個基礎的 widget prototype, 定義在?jQuery.Widget.prototype。當插件實例化時, 它會被用jQuery.data?的方式保存在原來的 DOM 元素里, 以插件名作為 key 值。
因為插件實例時直接綁定到 DOM 元素,你甚至可以直接訪問到插件實例而不用 繞經那些暴露出來的插件方法。這樣你就可以不用傳方法名的方式而是直接去調用實例方法, 實例的屬性也可以直接訪問了。
var bar = $("<div></div>").appendTo("body").progressbar().data("progressbar" );// call a method directly on the plugin instance bar.option("value", 50);// access properties on the plugin instance alert(bar.options.value);使用構造函數和 prototype 的方式來實現插件的一個最大的好處, 就是使擴展插件變得很簡單。通過修改插件的 prototype, 可以輕松的修改所有實例的行為。比如,你要添加一個方法用于重置進度為 0%, 只要給 prototype 添加這個方法,那么所有實例上都擁有這個功能了。
$.nmk.progressbar.prototype.reset = function() {this._setOption("value", 0); };清掃處理
有時候,插件讓用戶可以應用,然后過一陣再解除應用是有意義的。 這可以通過 destroy 方法的來實現。在?destroy?方法內部, 你應該取消你的插件能造成的所有修改,初始化過程中或者后面的使用中造成的。?destroy?方法在 DOM 刪除時會被自動調用,所以它可以用于垃圾回收。 默認的destroy?方法會刪掉 DOM 元素與插件實例直接的連接, 所以在覆蓋它時是調用原先插件提供的基礎?destroy?方法,是很重要的。
Example?8.11.?給 widget 添加 destroy 方法
$.widget( "nmk.progressbar", {options: {value: 0},_create: function() {this.element.addClass("progressbar");this._update();},_setOption: function(key, value) {this.options[key] = value;this._update();},_update: function() {var progress = this.options.value + "%";this.element.text(progress);if (this.options.value == 100 ) {this._trigger("complete", null, { value: 100 });}},destroy: function() {this.element.removeClass("progressbar").text("");// call the base destroy function$.Widget.prototype.destroy.call(this);} });結論
Widget factory 是創建有狀態的插件的唯一途徑。我們有不同的插件模型可供選用, 各有優缺。Widget factory 解決了大量基礎性問題,有助于提高效率,有利于代碼重用, 非常適合用來創建 jQuery UI 和其它有狀態的插件。
原文地址:http://www.cnblogs.com/timy/archive/2011/04/01/2001871.html
轉載于:https://www.cnblogs.com/wangyhua/p/4050580.html
總結
以上是生活随笔為你收集整理的使用 jQuery UI Widget Factory 编写有状态的插件(Stateful Plugins)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 橙光游戏《EXO-灵魂尽头》攻略04-1
- 下一篇: 女生头像和网名124个