惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

云风的 BLOG
云风的 BLOG
GbyAI
GbyAI
G
Google Developers Blog
Engineering at Meta
Engineering at Meta
月光博客
月光博客
腾讯CDC
Recent Announcements
Recent Announcements
酷 壳 – CoolShell
酷 壳 – CoolShell
爱范儿
爱范儿
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
S
SegmentFault 最新的问题
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
阮一峰的网络日志
阮一峰的网络日志
博客园 - 【当耐特】
The GitHub Blog
The GitHub Blog
Last Week in AI
Last Week in AI
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
aimingoo的专栏
aimingoo的专栏
Google DeepMind News
Google DeepMind News
Y
Y Combinator Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Martin Fowler
Martin Fowler
A
About on SuperTechFans
博客园 - 叶小钗

博客园 - Roamman

RRAS Access一些问题 临时表的一个用法 ConnectionString Microsoft SQL Server 错误代号: 15535 解决方法 百度也开源 位运算 之(1) 按位与(AND)& 操作 托管调试助手报错 类型初始值设定项引发异常 js 的开发效率 window.showModalDialog 以及window.open用法简介 Emterprise Library 学习地址 Web 开发与设计之 Google 兵器谱 Web 开发与设计之 Google 兵器谱 Web 开发与设计之 Google 兵器谱 Web 开发与设计之 Google 兵器谱 Web 开发与设计之 Google 兵器谱 Jquery Ajax时 error处理 之 parsererror jQuery工作原理解析以及源代码示例
jQuery Widget 开发指南
Roamman · 2010-02-02 · via 博客园 - Roamman

原文:http://bililite.com/blog/understanding-jquery-ui-widgets-a-tutorial/

由于翻译后不能使用HTML和SCRIPT所以演示部分就不能看到了,请参照原文。

写这篇文章的目的是为了让我理解并开发出我自己的Widgets,同时我也希望这篇文章能对其他人也有帮助。Widget让我说就是一种用户界面元素,类似于按钮或者像复杂的DatePicker(日期选择控件)。但这一概念对于jQuery,更确切的说是一个类。这个类的成员与一些HTML元素相关,比如Draggable和Sortable。当然不是所有Widget都使用$.widget,例如datePicker就没有使用。

插件:修改元素

让我们用一个带CSS类的P元素作为目标举个例子。

<p class="target">This is a paragraph</p>

我们把它变绿:

$(".target").css({"background":'green'});

然后我们需要将这一功能更通用化:

$.fn.green = function() {return this.css({background: 'green'})}

上面的代码是我们可以在任意的选中元素上产生效果,但他没有让我们保持和某个元素的关联。例如如果我们需要制作一个恢复背景的功能,哪么我们必须确定他的初始颜色。如果要设计一个Darker(),我们就必须知道元素现在是什么颜色。

保持插件状态

我们可以创建一个与某元素管理单的对象:


 element.myobject = new Myobject({'target': element})

$.fn.green2 = function() {

               return this.each(function(){

                        if (!this.green) this.green = new Green(this); // associate our state-keeping object with the element

                            this.green.setLevel(15);

                  });

           };

$.fn.off = function() {

              return this.each(function(){

                         if (this.green) this.green.setLevel(16);

                             delete this.green; // recover the memory

                });

            };

$.fn.darker = function() {

              return this.each(function(){

                       if (this.green) this.green.setLevel(this.green.getLevel()-1);

               });

           };

$.fn.lighter = function() {

             return this.each(function(){

                    if (this.green) this.green.setLevel(this.green.getLevel()+1);

              });

          };

function Green(target){

greenlevels = ['#000','#010','#020','#030','#040','#050','#060','#070','#080','#090','#0a0','#0b0','#0c0','#0d0','#0e0','#0f0','#fff'];

this.target = target; // associate the element with the object

this.level = 0;

this.getLevel = function() { return this.level; }

this.setLevel = function(x) {

this.level = Math.floor(Math.min(greenlevels.length-1, Math.max(0,x)));

this.target.css({background: greenlevels[this.level]});

}

};

但是上面这种方式使得$.fn命名空间中出现了很多函数。我们也可以在该命名空间内再创建一个命名空间,但一般的设计思路使用一个字符串来调用相应的函数,即我们可以使用类似element.green2("darker")来调用darker()方法:


$.fn.green2 = function(which){

        return this.each(function(){

           if (which === undefined){ // initial call

                if (!this.green) this.green = new Green($(this)); // associate our state-keeping object with the element

                      this.green.setLevel(15);

                }else if (which == 'off'){

                        if (this.green) this.green.setLevel(16);

                        delete this.green

               }else if (which == 'darker'){

                      if (this.green) this.green.setLevel(this.green.getLevel()-1);

               }else if (which == 'lighter'){

                     if (this.green) this.green.setLevel(this.green.getLevel()+1);

              }

          });

  };

function Green(target){

greenlevels = ['#000','#010','#020','#030','#040','#050','#060','#070','#080','#090','#0a0','#0b0','#0c0','#0d0','#0e0','#0f0', '#fff'];

this.target = target; // associate the element with the object

this.level = 0;

this.getLevel = function() { return this.level; }

this.setLevel = function(x) {

this.level = Math.floor(Math.min(greenlevels.length-1, Math.max(0,x)));

this.target.css({background: greenlevels[this.level]});

}

};

插件与对象关联所带来的问题
上面的方式能够方便的写出程序,但是也带来了循环引用和可能的内存漏洞。浏览器对于Javascript和Dom元素是使用不同的垃圾回收方式,上面的引用方式可能就会带来问题,使得回收不能正常进行。
我们同时也要注意,在我们开发插件是也要注意内存的回收。
jQuery用$.fn.data解决了这一问题:
 $(element).data('myobject', new Myobject({'target': element}))
但是,这样做的同时又带来了其他的问题,我们需要做很多“额外”的工作,这些工作与程序逻辑毫无关系,重复而无用。所以重复实现这一功能,需要抽象出来减少工作。
解决问题:$.widget
这就是$.widget出现的原因。它使得插件中的Javascript类的单个实例与每个元素相关联,这样我们在与对象进行交互操作元素的时候就不会带来内存绣楼的问题。
同上面一样,你还是需要创建类的构造函数。与之不同的是,我们需要一个包含了相关方法的“原型”。同时也有一些变化,如:_init()函数在构造是调用,destroy()方法在析构是调用。这两个函数都是预先定义的,不过你可以覆盖。element和上面我们的target是与类相关的jQuery对象。
Widget中所有已“_”开头的方法都属预定义似有形函数,外部不能调用。 
 var Green3 = { 
_init: function() { this.setLevel(15); }, 
 greenlevels: ['#000','#010','#020','#030','#040','#050','#060','#070','#080','#090','#0a0','#0b0','#0c0','#0d0','#0e0','#0f0', '#fff'], 
 level: 0, 
 getLevel: function() { return this.level; }, 
 setLevel: function(x) { this.level = Math.floor(Math.min(this.greenlevels.length-1, Math.max(0,x))); 
 this.element.css({background: this.greenlevels[this.level]}); }, 
 darker: function() { this.setLevel(this.getLevel()-1); }, 
 lighter: function() { this.setLevel(this.getLevel()+1); }, 
 off: function() {this.element.css({background: 'none'}); 
 this.destroy(); // use the predefined function } 
 }; 

上述代码即就是整个程序逻辑,使用下面代码生成插件:

$.widget("ui.green3", Green3); // create the widget

转载:http://terry.blog.35.cn/2009/07/12/jquery-widget-%E5%BC%80%E5%8F%91-tutorial-%E7%BF%BB%E8%AF%91%E7%89%88/