一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

編寫jQueryUI插件(widget)

 JS資料庫(kù) 2014-07-30

使用jQueryUI的widget來寫插件,相比于基本的jquery插件有一些好處:

* 方便實(shí)現(xiàn)繼承,代碼重用

* 默認(rèn)是單例

* widget已經(jīng)給你實(shí)現(xiàn)好的一些常用方法,例如destroy

帶來好處的同時(shí)也帶來了荊棘和陷阱,本文的目的就是梳理這些荊棘,標(biāo)出哪里有陷阱。

 

基本知識(shí):命名規(guī)范,public, private, this, this.element

如何開始寫一個(gè)widget呢?模板如下:

(function ($) {
    // utility functions (won’t be inherited)
    function foo() {}
    
    $.widget('命名空間.插件名', $.繼承插件的命名空間.插件名,{ /* snip */ });
})(jQuery);        

其中命名空間是可選的,要不要繼承別的widget也是可選的。大頭是后面snip的部分,這也是下文要講的。

一般來說工具函數(shù)寫在widget外面比較合適,但如果你想要這些工具函數(shù)被子類繼承,則需要寫在widget里面。

寫在widget里面的,就有public和private之分,規(guī)則是:

public方法首字符不是_

private方法首字符是_


當(dāng)調(diào)用方法時(shí),會(huì)先判斷是否以_開頭,如果是則不執(zhí)行調(diào)用。

如果我非要在外面調(diào)用private方法,該怎么做?并非一點(diǎn)辦法也沒有:

var instance = $('<div>');
instance.mywidget('publicFunction'); // work
instance.mywidget('_privateFunction'); // silently fail
instance.data('mywidget')._privateFunction(); // work
$.mynamespace.mywidget.prototype._privateFunction(); // work
 

在widget內(nèi),this表示的是什么?我們?cè)趙idget的一個(gè)public函數(shù)內(nèi)用console.log(this)打出來瞧瞧:

image

日志顯示,this是一個(gè)$.widget.$.(anonymous function).(anonymous function)

this.element是變成widget的那個(gè)jQuery對(duì)象,如果要用jquery的方法,往往首先要取到j(luò)query對(duì)象。

this.options是插件的選項(xiàng),下文會(huì)詳解。

this.__proto__包含了插件中定義的所有public和private函數(shù),以及繼承過來的方法。

這里簡(jiǎn)單介紹一下__proto__:每個(gè)對(duì)象都會(huì)在其內(nèi)部初始化一個(gè)屬性,就是__proto__,當(dāng)我們?cè)L問一個(gè)對(duì)象的屬性 時(shí),如果這個(gè)對(duì)象內(nèi)部不存在這個(gè)屬性,那么他就會(huì)去__proto__里找這個(gè)屬性,這個(gè)__proto__又會(huì)有自己的__proto__,于是就這樣 一直找下去,也就是我們平時(shí)所說的原型鏈的概念。

_create  _init    destroy

widget factory實(shí)現(xiàn)了一種單例模式,即不允許在同一個(gè)jQuery對(duì)象上多次實(shí)例化。

當(dāng)調(diào)用$(XX).widgetName()進(jìn)行初始化的時(shí)候,會(huì)執(zhí)行以下代碼(源碼截取自jquery.ui.widget.js):

var instance = $.data( this, name ); // 從widget自身取出名字為name的數(shù)據(jù)
if ( instance ) {
    instance.option( options || {} )._init();  // 若該數(shù)據(jù)已經(jīng)存在則只調(diào)用_init
} else {
    $.data( this, name, new object( options, this ) ); // 若數(shù)據(jù)還沒有則新建一個(gè)實(shí)例,并將實(shí)例保存
}

 

當(dāng)調(diào)用$(XX).widgetName(‘destroy’)進(jìn)行銷毀的時(shí)候,執(zhí)行以下代碼(源碼截取自jquery.ui.widget.js):

this.element
    .unbind( "." + this.widgetName )
    .removeData( this.widgetName ); // 刪除在create時(shí)保存的數(shù)據(jù) 

有一個(gè)removeData的操作,那么下次調(diào)用$(XX).widgetName()就會(huì)重新實(shí)例化了。

 

需要注意的是,destroy方法在jquery.ui.widget.js中是有默認(rèn)實(shí)現(xiàn)的,而_create和_init沒有實(shí)現(xiàn)。因此如果用自己的方法覆蓋destroy,不要忘記調(diào)用默認(rèn)的

destory: function () {
    console.log('destory');

    // call the original destroy method since we overwrote it
    $.Widget.prototype.destroy.call(this);
}

 

以下示例代碼驗(yàn)證_create和_init的區(qū)別以及destroy的作用:

var mw = $('#test').myWidget(); // _create  _init
mw = $('#test').myWidget(); // _init
mw.myWidget('destory');
mw = $('#test').myWidget(); // _create  _init

 

那么在_create和_init以及destroy里分別應(yīng)該做什么:

_create: 生成HTML,事件綁定。

_init: 執(zhí)行默認(rèn)的初始化動(dòng)作,例如把頁(yè)面變成初始狀態(tài)。

destory: 調(diào)用$.Widget.prototype.destroy.call(this),刪除HTML。

 

注意:綁定事件要注意給事件名加命名空間后綴:例如 .bind('mouseenter.mywidget', this._hover)

 

options

選項(xiàng),在widget中的定義是options,而在調(diào)用時(shí)是option,注意定義的時(shí)候有s,調(diào)用的時(shí)候沒s。

定義:

option

s

: {
    field1: 'default',
    function1: function () {
        console.log('default option function1');
    }
},

調(diào)用:

$('#test').mywidget('option', 'field1', 2);

widget默認(rèn)實(shí)現(xiàn)了兩個(gè)函數(shù):_setOptions和_setOption,_setOptions的實(shí)現(xiàn)就是對(duì)每個(gè)要修改的option調(diào)用_setOption,也就是說真正修改的動(dòng)作在_setOption里。因此,如果要重寫_setOption函數(shù),則一定不要忘記寫

$.Widget.prototype._setOption.apply(this, arguments);

 

_setOptions和_setOption這倆函數(shù)什么時(shí)候被調(diào)用呢?用下面這個(gè)例子來說明。

例如有這樣的_setOption和_setOptions:

 
_setOption: function (key, value) {
    console.log('_setOption: key=%s  value=%s', key, value);
    $.Widget.prototype._setOption.apply(this, arguments);
},

_setOptions: function (options) {
    var key;

    console.group('_setOptions');
    for (key in options) {
        this._setOption(key, options[key]);
    }
    console.groupEnd();

    return this;
},

以及一個(gè)打印options值的函數(shù)printOptions:

printOptions: function () {
    console.group('options');
    console.log('field1: %s', this.options.field1);
    console.log('function1: %s', this.options.function1);
    console.groupEnd();
},

我們像下面這樣調(diào)用:

var instance = $('<div>');

// create widget with default options
console.group();

instance.mywidget(); 
instance.mywidget('printOptions');

console.groupEnd();

// create widget with specified options
instance.mywidget('destroy');
console.group();

var opts = {
    field1: 'specified',
    function1: function () {
        console.log('specified option function1');
    },
};
instance.mywidget(opts); 
instance.mywidget('printOptions');

console.log('-------------');
instance.mywidget(opts); 

console.groupEnd();

// modify options
console.group();

instance.mywidget('option', 'field1', 2);
instance.mywidget('printOptions');

console.groupEnd();
 

打出的日志如下:

image

日志分為三大塊。

第一塊是不使用options來初始化,可以看到直接使用定義里默認(rèn)的options,是不調(diào)用_setOption的。

第二塊是使用options來初始化,這一塊做了兩個(gè)實(shí)驗(yàn)(日志中用--------將兩塊分隔),第一個(gè)實(shí)驗(yàn)是完全重建(_create, _init),從日志可以看到并沒有調(diào)用_setOption;第二個(gè)實(shí)驗(yàn)只是重新初始化(_init),用的options都一樣,從日志可以看到它調(diào)用了_setOption,且在_init之前調(diào)用的。

第三塊不是初始化,而僅僅是修改option值,可以清楚看到調(diào)用了_setOption。

 

何時(shí)會(huì)調(diào)用_setOption的結(jié)論:

1. 像instance.mywidget('option', 'field1', 2); 這樣顯式設(shè)置option時(shí)。

2. 帶著options初始化時(shí):

如果實(shí)例不存在,即需要調(diào)用_create,則不調(diào)用_setOption;

如果實(shí)例已存在,僅需要調(diào)用_init,則會(huì)在調(diào)用_init之前調(diào)用_setOption。

 

 

_trigger

注意這個(gè)_trigger是jQueryUI widget factory里的,和jQuery里$.fn命名空間下的trigger函數(shù)不是一個(gè)東西(后者不帶下劃線)。

_trigger一般用來回調(diào)用戶傳入options的callback。

在插件內(nèi)部調(diào)用_trigger(‘myEvent’)即相當(dāng)于調(diào)用options里面的myEvent這個(gè)回調(diào)函數(shù)。

要改動(dòng)options里的event handler應(yīng)該怎么做呢?不要使用bind/unbind,而是去修改options:

// bind (overwrite, not add event handler)
mw.myWidget('option', 'myEvent', function (event, ui) {
    console.log('new implement');
});
// unbind
mw.myWidget('option', 'myEvent', null);

 

總結(jié)一下:

this._trigger(‘eventName’)是widget特有的,用于調(diào)用options里定義的callback。

this.element.trigger(‘eventName’)是jQuery的,可參考jQuery的事件的用法。(其中this.element是表示該插件的jQuery對(duì)象)

 

一個(gè)_trigger的樣例:

// 模板
this._trigger( "callbackName" , [eventObject], [uiObject] )

callbackNameThe name of the event you want to dispatcheventObject(Optional)An (mocked) event object. _trigger wraps this object and stores it in event.originalEventThe user receives an object with event.type == this.widgetEventPrefix + "eventname"uiObject(Optional)An object containing useful properties the user may need to access.Protip: Use a method like ._uito generate objects with a consistent schema. 

// 調(diào)用樣例
this._trigger( "hover", e /* e.type == "mouseenter" */, { hovered: $(e.target)});
// The user can subscribe using an init option
$("#elem").filterable( { hover: function(e,ui) { } } );
// Or with traditional event binding/delegation
$("#elem").bind( "filterablehover" , function(e,ui) { } );

 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    国产又粗又猛又大爽又黄同志| 青青操在线视频精品视频| 粉嫩一区二区三区粉嫩视频| 亚洲精品福利入口在线| 老熟妇乱视频一区二区| 伊人色综合久久伊人婷婷| 激情爱爱一区二区三区| av免费视屏在线观看| 日韩精品中文字幕在线视频| 国产在线视频好看不卡| 日韩欧美一区二区不卡视频| 香蕉尹人视频在线精品| 亚洲中文字幕高清乱码毛片 | 成年午夜在线免费视频| 欧美日韩综合综合久久久| 国产一区二区三区四区中文| 很黄很污在线免费观看| 精品老司机视频在线观看| 日本淫片一区二区三区| 国产亚洲午夜高清国产拍精品| 日韩精品综合福利在线观看| 日韩黄色大片免费在线| 日本妇女高清一区二区三区| 欧美黑人在线精品极品| 91亚洲精品综合久久| 黄色污污在线免费观看| 中文字幕日产乱码一区二区| 久久精品国产亚洲av麻豆| 国产又猛又大又长又粗| 国产高清一区二区白浆| 欧美二区视频在线观看| 国产一区欧美午夜福利| 中国日韩一级黄色大片| 亚洲精品成人综合色在线| 黑丝袜美女老师的小逼逼| 亚洲精品一区三区三区| 欧美激情床戏一区二区三| 日韩成人高清免费在线| 欧美日韩中黄片免费看| 午夜国产成人福利视频| 欧美日不卡无在线一区|