使用 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)相关推荐

  1. jQuery 使用 jQuery UI 部件工厂编写带状态的插件(翻译)

    首先,我们要创建一个progress bar,它只允许我们简单的设置进度值.正如我们接下来将要看到的,我们需要通过调用 jQuery.widget 及其两个参数来实现这一操作,这两个参数分别是:将要创 ...

  2. jQuery UI Widget(1.8.1)工作原理--转载

    先看下代码的相关注释: /*!* jQuery UI Widget 1.8.1** Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) ...

  3. jQuery ui widget和jQuery plugin的实现原理简单比较

    一.创建 1.  jQuery plugin (function($){ $.fn.MyPlugin=function(){ //js代码 } })(jQuery) 为了与页面上其他代码友好相处,将p ...

  4. html5拖动的面板 panel,基于jQuery UI的Bootstrap Panel面板功能增强插件

    LobiPanel是一款基于jQuery UI的Bootstrap Panel面板功能增强插件.通过该插件可以为Bootstrap的原生Panel面板增加编辑标题,最大化,最小化,面板拖动关闭面板等功 ...

  5. 基于 jquery ui 扩展Widget

    jQuery UI CSS Framework是jQuery UI中的一个样式框架,可以利用jQuery Theme roller 来生成自己想要的css样式效果.我们可以利用jQuery UI的一些 ...

  6. jquery ui 主题_使用jQuery UI主题

    主题不是一个新概念. 您可能已经使用级联样式表(CSS)样式和类推出了一些样式,以格式化网站的外观. 使用框架可以使方法标准化,并减少需要编写的工作量和代码量. jQuery UI现在是主题实现的行业 ...

  7. 学习 jQuery UI

    jQuery UI 是以 jQuery 为基础的开源 JavaScript 网页用户界面代码库.包含底层用户交互.动画.特效和可更换主题的可视控件.我们可以直接用它来构建具有很好交互性的web应用程序 ...

  8. Dijit、ExtJS、jQuery UI 异同浅析

    钟思奇是 IBM CDL 的一名软件工程师,主要从事 Dojo 控件库及基于 J2EE 的项目开发,热衷于学习各类新技术. 王 修文, 软件工程师, Sungard 王修文是 Sungard SGT ...

  9. jQuery UI Autocomplete示例(一)

    今天看到这么个教程,分享给新手学习 AutoComplete 在获取焦点后,随着用户键入的内容,可以在预订的数据源中查找和已输入的内容相匹配的内容列表供用户选择. 这可以用作之前输入过的内容也可以用作 ...

最新文章

  1. c++对象模型之Data布局
  2. 使用SAE和Gitcafe开发网站应用
  3. 物料凭证不产生会计凭证的几种情况
  4. 军营中重重打击之后,我变了一个人(上)--我成为程序员所经历的(四)
  5. 材料二电子计算机及网络技术有限公司,高等职业教育计算机网络技术专业(三二分段)备案材料.doc...
  6. 安卓手机qq怎么看密友值_qq亲密关系分数值是什么在哪看 怎么查情侣值或闺蜜值方法...
  7. golang 相互引用_Golang与C互用以及调用C的so动态库和a静态库
  8. 如何利用大数据技术构建用户画像
  9. tcp/ip ---IP路由选择
  10. tar,jar,war的区别
  11. java期末考试工程项目_java web 期末项目实验源码20套,自用学习非常不错!
  12. “李记餐厅”微信点餐小程序的设计与实现
  13. 最大网络流的多种解法(洛谷P3376 网络最大流 为例)
  14. 单片机闪灯c语言,PIC单片机入门之闪灯程序
  15. 从档案信息管理到档案知识管理
  16. 选择粘贴性无html,用好Office的选择性粘贴
  17. Visual Studio Code 基本插件
  18. 每天学一点英文:Espresso 20210903
  19. Docker容器数据卷
  20. 关于TCP/IP通信协议的一些见解

热门文章

  1. 转贴:Hyper-V的几款免费管理工具
  2. SpringBoot2.0实现静态资源版本控制
  3. windows8.1如何分盘
  4. msp430项目编程53
  5. Yii2几个要注意的小地方
  6. 学习网站分享 - 菜鸟教程
  7. 推公式hdu2298
  8. java 集合类简单的分析1
  9. 详细解读Spring2.5 +Struts1.3 框架(使用Spring声明式事物管理和springjjdbc模板)
  10. Socket套接字的速率控制(linux)