编写jQueryUI插件(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] )
callbackName
The name of the event you want to dispatcheventObject
(Optional)An (mocked) event object. _trigger
wraps this object and stores it in event.originalEvent
The 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 ._ui
to 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/dc10101/archive/2012/05/03/2481004.html
编写jQueryUI插件(widget)相关推荐
- flutter插件进阶之手把手教你编写简易插件(五)
经过前面几篇文章中对flutter插件相关技术的介绍,本篇我们从1开始手把手的进行插件代码的编写工作,以实现一个简单的桌面小部件功能. 来吧,效果展示来一波~~ 目录: 五.编写简易插件(安卓桌面小部 ...
- Flutter 项目编写 第三方插件库文件引入,本地图片 json数据引入解析
FlutterDemo是如何一步一步搭建起来的 最初就是直接新建flutter项目,就会自动建立一个入门项目.(开始项目前,需先学习Dart语言) flutter项目代码都在lib目录下编写: 新建包 ...
- 使用Qt编写模块化插件式应用程序
动态链接库技术使软件工程师们兽血沸腾,它使得应用系统(程序)可以以二进制模块的形式灵活地组建起来.比起源码级别的模块化,二进制级别的模块划分使得各模块更加独立,各模块可以分别编译和链接,模块的升级不会 ...
- skywalking原理_Skywalking系列博客6手把手教你编写 Skywalking 插件
点击上方 IT牧场 ,选择 置顶或者星标技术干货每日送达! 前置知识 在正式进入编写环节之前,建议先花一点时间了解下javaagent(这是JDK 5引入的一个玩意儿,最好了解下其工作原理):另外,S ...
- 编写OD插件将IDA中分析出来的函数名导入到OD中
逆向程序的时候,喜欢用IDA静态分析,用OD动态调试,如果把IDA分析出来的函数名称都导入到OD中,调试的时候就知道哪些函数不需要再看了.以前我一直用GODUP的map loader,但是有些时候感觉 ...
- 使用Lua编写whireshark插件
whireshark支持Lua.C.C++编写的插件 在这里,我简单介绍如何使用Lua编写whireshark插件. 一.插件的存放位置 whireshark插件分为个人插件和全局插件,在window ...
- 自己编写jQuery插件之表单验证
自己编写jQuery插件之表单验证 吐个嘈先:最近状态不咋滴,真是什么都不想干,不想上班,做什么都没动力,觉得没意思.不想这样,不想这样,快让这种情绪消失吧,忽忽.... 表单验证在项目中用的还是比较 ...
- 如何编写 Nagios 插件 (http://zener.blog.51cto.com/937811/727685)
如何编写 Nagios 插件 Nagios 的最激动人心的方面是可以轻松地编写您自己的插件,只需要了解一些简单的指导原则即可.为了管理插件,Nagios 每次在查询一个服务的状态时,产生一个子进程,并 ...
- maven插件编写_编写Maven插件的提示
maven插件编写 最近,我花了很多时间为Maven编写插件或在其中工作. 它们简单,有趣且有趣. 我以为我会分享一些技巧,使编写它们时的生活更轻松. 提示1:将任务与Mojo分开 最初,您将把moj ...
最新文章
- 3.Chrome数据同步服务分析--server一片
- jira无法访问此网站_天津制作网站公司:更换空间对网站SEO的影响
- 用python画猪_用python画小猪票佩奇
- rocketmq中producer设计与实现
- 一个Google Chrome浏览器的英文字典扩展应用
- python如何确定拐点_如何确认均线拐点的实战技巧和理论(图解)
- kettle下载安装和连接
- RubyOnRails终极部署
- android时间为什么没有更新了,万年历插件_中华万年历小插件为什么不自己更新日期时间...
- win11任务栏图标大小设置教程
- pytorch第四课
- Linux设置登录密码错误次数限制
- Baumer工业相机堡盟相机使用CameraExplorer软件进行相机参数保存与 UserSet参数设置
- 安规之电气间距和爬电距离
- CMM与CMMI对比
- Java人才,请往这里看过来!
- 【RISC-V】Trap和Exception
- 如何去除惠普战66的扬声器杂音
- AUTOCAD——构造线
- Java学习20天 String 类 常用方法 String、StringBuffer、StringBuilder三者的异同
热门文章
- android c聊天功能,Android实现简单C/S聊天室应用
- show在php,show.php
- 安卓饼状图设置软件_话单及银行卡交易智能分析软件
- java this final_Java this、final等关键字总结
- python 虚拟现实_虚拟现实 | MOOC中国 - 慕课改变你,你改变世界
- 封装一个计时器,记录页面的停留时间
- Ant Design 入门-参照官方文档使用组件
- Swift default参数
- python基础===拆分字符串,和拼接字符串
- ArrayList的内存泄露