博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
jquery-ui-widget
阅读量:7027 次
发布时间:2019-06-28

本文共 6106 字,大约阅读时间需要 20 分钟。

使用jQueryUI的widget来写插件,相比于基本的jquery插件有一些好处:

* 方便实现继承,代码重用

* 默认是单例

* widget已经给你实现好的一些常用方法,例如destroy

带来好处的同时也带来了荆棘和陷阱,本文的目的就是梳理这些荆棘,标出哪里有陷阱。

 

基本知识:命名规范,public, private, this, this.element

如何开始写一个widget呢?模板如下:

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

其中命名空间是可选的,要不要继承别的widget也是可选的。大头是后面snip的部分,这也是下文要讲的。

一般来说工具函数写在widget外面比较合适,但如果你想要这些工具函数被子类继承,则需要写在widget里面。

写在widget里面的,就有public和private之分,规则是:

public方法首字符不是_

private方法首字符是_

当调用方法时,会先判断是否以_开头,如果是则不执行调用。

如果我非要在外面调用private方法,该怎么做?并非一点办法也没有:

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

在widget内,this表示的是什么?我们在widget的一个public函数内用console.log(this)打出来瞧瞧:

日志显示,this是一个$.widget.$.(anonymous function).(anonymous function)

this.element是变成widget的那个jQuery对象,如果要用jquery的方法,往往首先要取到jquery对象。

this.options是插件的选项,下文会详解。

this.__proto__包含了插件中定义的所有public和private函数,以及继承过来的方法。

这里简单介绍一下__proto__:每个对象都会在其内部初始化一个属性,就是__proto__,当我们访问一个对象的属性 时,如果这个对象内部不存在这个属性,那么他就会去__proto__里找这个属性,这个__proto__又会有自己的__proto__,于是就这样 一直找下去,也就是我们平时所说的原型链的概念。

_create  _init    destroy

widget factory实现了一种单例模式,即不允许在同一个jQuery对象上多次实例化。

当调用$(XX).widgetName()进行初始化的时候,会执行以下代码(源码截取自jquery.ui.widget.js):

var instance = $.data( this, name ); // 从widget自身取出名字为name的数据if ( instance ) {    instance.option( options || {} )._init();  // 若该数据已经存在则只调用_init } else { $.data( this, name, new object( options, this ) ); // 若数据还没有则新建一个实例,并将实例保存 }

 

当调用$(XX).widgetName(‘destroy’)进行销毁的时候,执行以下代码(源码截取自jquery.ui.widget.js):

this.element    .unbind( "." + this.widgetName )    .removeData( this.widgetName ); // 删除在create时保存的数据

有一个removeData的操作,那么下次调用$(XX).widgetName()就会重新实例化了。

 

需要注意的是,destroy方法在jquery.ui.widget.js中是有默认实现的,而_create和_init没有实现。因此如果用自己的方法覆盖destroy,不要忘记调用默认的:

destory: function () {    console.log('destory');    // call the original destroy method since we overwrote it    $.Widget.prototype.destroy.call(this);}

 

以下示例代码验证_create和_init的区别以及destroy的作用:

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

 

那么在_create和_init以及destroy里分别应该做什么:

_create: 生成HTML,事件绑定。

_init: 执行默认的初始化动作,例如把页面变成初始状态。

destory: 调用$.Widget.prototype.destroy.call(this),删除HTML。

 

注意:绑定事件要注意给事件名加命名空间后缀:例如 .bind('mouseenter.mywidget', this._hover)

 

options

选项,在widget中的定义是options,而在调用时是option,注意定义的时候有s,调用的时候没s。

定义:

option

s

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

调用:

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

widget默认实现了两个函数:_setOptions和_setOption,_setOptions的实现就是对每个要修改的option调用_setOption,也就是说真正修改的动作在_setOption里。因此,如果要重写_setOption函数,则一定不要忘记写:

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

 

_setOptions和_setOption这俩函数什么时候被调用呢?用下面这个例子来说明。

例如有这样的_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; },

以及一个打印options值的函数printOptions:

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

我们像下面这样调用:

var instance = $('
');// create widget with default optionsconsole.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();
 

打出的日志如下:

日志分为三大块。

第一块是不使用options来初始化,可以看到直接使用定义里默认的options,是不调用_setOption的。

第二块是使用options来初始化,这一块做了两个实验(日志中用--------将两块分隔),第一个实验是完全重建(_create, _init),从日志可以看到并没有调用_setOption;第二个实验只是重新初始化(_init),用的options都一样,从日志可以看到它调 用了_setOption,且在_init之前调用的。

第三块不是初始化,而仅仅是修改option值,可以清楚看到调用了_setOption。

 

何时会调用_setOption的结论:

1. 像instance.mywidget('option', 'field1', 2); 这样显式设置option时。

2. 带着options初始化时:

如果实例不存在,即需要调用_create,则不调用_setOption;

如果实例已存在,仅需要调用_init,则会在调用_init之前调用_setOption。

 

 

_trigger

注意这个_trigger是jQueryUI widget factory里的,和jQuery里$.fn命名空间下的trigger函数不是一个东西(后者不带下划线)。

_trigger一般用来回调用户传入options的callback。

在插件内部调用_trigger(‘myEvent’)即相当于调用options里面的myEvent这个回调函数。

要改动options里的event handler应该怎么做呢?不要使用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);

 

总结一下:

this._trigger(‘eventName’)是widget特有的,用于调用options里定义的callback。

this.element.trigger(‘eventName’)是jQuery的,可参考jQuery的事件的用法。(其中this.element是表示该插件的jQuery对象)

 

一个_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. 

// 调用样例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) { } );

转载于:https://www.cnblogs.com/widow/p/4447899.html

你可能感兴趣的文章
Spring的两种常见的注入
查看>>
使用命令设置ubuntu8.10的ip及DNS
查看>>
[转]DPM2012系列之十一:还原exchange 2010数据库
查看>>
object-python-监控服务器负载-nagios-plug
查看>>
response.redirect 调转到新页面报错
查看>>
ios-设计模式-单例
查看>>
linux NFS 配置
查看>>
我的友情链接
查看>>
一些比较好的javaEE/ wildfly Demo
查看>>
mantis 在linux 下的安装使用
查看>>
exchange 2010 sp2 后续之日常维护脚本
查看>>
云计算分布式架构综述
查看>>
C++编程必备
查看>>
我的友情链接
查看>>
手把手教你使用cocosbuilder在cocos2d-x中建立单独骨骼动画文件(三)
查看>>
Java访问远程服务
查看>>
shell脚本编程总结
查看>>
新风系统是否真的有存在的必要呢?
查看>>
iOS开发之初识xib
查看>>
EJB 简单开发流程
查看>>