jquery-ui-widget
使用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 = $('<div>');
instance.mywidget('publicFunction'); // work
instance.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 _init
mw = $('#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 = $('<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();
打出的日志如下:

日志分为三大块。
第一块是不使用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) { } );
jquery-ui-widget的更多相关文章
- Jquery ui widget开发
Jquery ui 提供了一些基本的widget,但是他提供了很好的机制来创建widget.在jquery css framework中包含了基本的css样式(视觉和感觉诸如颜色,字体大小,图标等), ...
- 使用 jQuery UI Widget Factory 编写有状态的插件(Stateful Plugins)
使用 jQuery UI Widget Factory 编写有状态的插件(Stateful Plugins) Note 这一章节的内容是基于 Scott Gonzalez 一篇博客 Building ...
- JQuery UI Widget Factory官方Demo
<!doctype html> <html lang="en"> <head> <meta charset="utf-8&quo ...
- jQuery UI Widget(1.8.1)工作原理--转载
先看下代码的相关注释: /*! * jQuery UI Widget 1.8.1 * * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/abo ...
- jQuery UI Widget 原理
先看下代码的相关注释: /*! * jQuery UI Widget 1.8.1 * * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/abo ...
- 通过扩展jQuery UI Widget Factory实现手动调整Accordion高度
□ 实现Accordion高度一致 <head> <meta name="viewport" content="width=device-width&q ...
- jquery ui widget 源代码分析
jquery ui 的全部组件都是基于一个简单,可重用的widget. 这个widget是jquery ui的核心部分,有用它能实现一致的API.创建有状态的插件,而无需关心插件的内部转换. $.wi ...
- jQuery UI Widget(1.8.1)工作原理
/*! * jQuery UI Widget 1.8.1 * * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) * Dual l ...
- jQuery UI Widget Factory
https://learn.jquery.com/jquery-ui/widget-factory/ The jQuery UI Widget Factory is an extensible bas ...
- jquery.ui.widget详解
案例详解 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <titl ...
随机推荐
- postgresql 在linux上的源码安装
http://my.oschina.net/hippora/blog/375292 下载源码并解压 [root@fnddb ~]# wget https://ftp.postgresql.org/pu ...
- 在win7/8/10鼠标右键添加“管理员取得所有权”
Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\*\Shell\TakeAuthority]"icon"=" ...
- over-float清除浮动++隐藏溢出
overflow:hidden这个CSS样式是大家常用到的CSS样式,但是大多数人对这个样式的理解仅仅局限于隐藏溢出,而对于清除浮动这个含义不是很了解.一提到清除浮动,我们就会想到另外一个CSS样式: ...
- poj 3020 Antenna Placement (最小路径覆盖)
二分图题目 当时看到网上有人的博客写着最小边覆盖,也有人写最小路径覆盖,我就有点方了,斌哥(kuangbin)的博客上只给了代码,没有解释,但是现在我还是明白了,这是个最小路径覆盖(因为我现在还不知道 ...
- C#无边框窗体移动 将事件绑定到想实现的控件上
[DllImport("user32.dll")] public static extern bool ReleaseCapture(); [DllImport("use ...
- Dev之ChartControl控件(二)— 绘制多重坐标图形
有时针对一个ChartControl控件可能要设置多个Y轴,进行显示: 以下举个例子:如在一个Chart中显示多个指标项如图: 首先,读取数据,并对左边的Y轴最大和最小值进行设定 IndexSerie ...
- Review Board的使用
代码审核工具.先在命令行界面,进入到工程的Main目录下,然后使用命令 svn diff>yus.diff 这样就将Main里面的所有内容生成了,然后在浏览器里进入到自己的Review Boa ...
- Ubuntu 14.04 待机死机问题原来是自己改了这个配置
使用专有驱动没问题.使用开源驱动就会死机.驱动还是厂商的好@@
- JSP内置对象--web安全性及config对象的使用 (了解即可)
tomcat服务器配置的时候,在虚拟目录中必须存在一个WEB-INF文件夹,但是访问的时候并不能发现这个文件夹.改成WEB-INFs就可以看到. 所以WEB-INF文件夹不轻易让用户看到,那么其安全性 ...
- access restriction
一.既然存在访问规则,那么修改访问规则即可.打开项目的Build Path Configuration页面,打开报错的JAR包,选中Access rules条目,选择右侧的编辑按钮,添加一个访问规则即 ...