0%
这是一片思考的空间 -- arthinking
Spring 重构&代码整洁之道 软件设计 JVM 并发编程 数据结构与算法 分布式 存储 网络 微服务 设计模式
Java技术栈 - 涉及Java技术体系

jQuery插件的编写相关技术 设计总结和最佳实践

1、声明插件名称:

添加一个函数到jQuery.fn(jQuery.prototype)对象,该函数的名称就是你的插件名称:

jQuery.fn.myPlugin = function() {

// Do your awesome plugin stuff here

};

在命名不与jQuery其他函数冲突的情况,可以使用闭包的方式使用$符号:

(function( $ ) {
$.fn.myPlugin = function() {

// Do your awesome plugin stuff here

};
})( jQuery );

2、插件中的上下文:

jQuery接收一个回调,该回调本身就指向了dom,直接使用this就相当于我们平时的$(this)的情况:

(function( $ ){

$.fn.myPlugin = function() {

// there's no need to do $(this) because
// "this" is already a jquery object

// $(this) would be the same as $($('#element'));

this.fadeIn('normal', function(){

  // the this keyword is a DOM element

});

};
})( jQuery );
$('#element').myPlugin();

下面是一个简单的jQuery插件,实现获取所有div的最大高度:

(function( $ ){

$.fn.maxHeight = function() {

var max = 0;

this.each(function() {
  max = Math.max( max, $(this).height() );
});

return max;

};
})( jQuery );
var tallest = $('div').maxHeight(); // Returns the height of the tallest div

3、维护链接性:

前面的示例返回一个整数值最高的div,但是通常的意图仅在某种程度上是仅修改插件的元素集合,并将它们传递到下一个链中的方法。这样的jQuery的设计优雅的地方。所以保持链接性放到一个插件,您必须确保您的插件返回这个关键字。

(function( $ ){

$.fn.lockDimensions = function( type ) {

return this.each(function() {

  var $this = $(this);

  if ( !type || type == 'width' ) {
    $this.width( $this.width() );
  }

  if ( !type || type == 'height' ) {
    $this.height( $this.height() );
  }

});

};
})( jQuery );
$('div').lockDimensions('width').css('color', 'red');

因为插件返回this关键字的范围,它维护链接性,jQuery可以继续利用jQuery方法,如. css。所以,如果你的插件不返回一个内在价值,你应该总是返回this。

4、参数的传递,Defaults和Options:

(function( $ ){

$.fn.tooltip = function( options ) {

// Create some defaults, extending them with any options that were provided
var settings = $.extend( {
  'location'         : 'top',
  'background-color' : 'blue'
}, options);

return this.each(function() {        

  // Tooltip plugin code here

});

};
})( jQuery );
$('div').tooltip({
'location' : 'left'
});

通过$.extend合并默认参数和调用者传入的参数。

5、命名空间:

正确的命名空间在插件开发中是一个非常重要的部分。正确的命名空间,可以确保你的插件将有一个很低的几率在同一个页面上被他插件或代码覆盖。

在任何情况下都不应该在一个插件的jQuery.fn对象中声称多个名称空间。

(function( $ ){

$.fn.tooltip = function( options ) {
// THIS
};
$.fn.tooltipShow = function( ) {
// IS
};
$.fn.tooltipHide = function( ) {
// BAD
};
$.fn.tooltipUpdate = function( content ) {
// !!!
};

})( jQuery );

你应该收集所有的方法到一个对象化字面,并且通过方法的字面值进行调用:

(function( $ ){

var methods = {
init : function( options ) {
// THIS
},
show : function( ) {
// IS
},
hide : function( ) {
// GOOD
},
update : function( content ) {
// !!!
}
};

$.fn.tooltip = function( method ) {

// Method calling logic
if ( methods[method] ) {
  return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof method === 'object' || ! method ) {
  return methods.init.apply( this, arguments );
} else {
  $.error( 'Method ' \+  method + ' does not exist on jQuery.tooltip' );
}    

};

})( jQuery );

// calls the init method
$('div').tooltip();

// calls the init method
$('div').tooltip({
foo : 'bar'
});
// calls the hide method
$('div').tooltip('hide');
// calls the update method
$('div').tooltip('update', 'This is the new tooltip content!');

这种类型的方法封装和体系结构在jQuery插件社区中是一个标准,它适用于无数的插件,包括jQueryUI插件和小部件。

6、Events:

Bind方法允许通过命名空间的方式绑定事件,如果你的插件绑定了事件,可以通过命名空间的方式,在解除绑定事件时,你也可以这样做,来防止影响到其他的事件。可以通过“.” 的方式来设置绑定事件的命名空间。

(function( $ ){

var methods = {
init : function( options ) {

   return this.each(function(){
     $(window).bind('resize.tooltip', methods.reposition);
   });

 },
 destroy : function( ) {

   return this.each(function(){
     $(window).unbind('.tooltip');
   })

 },
 reposition : function( ) { 
   // ... 
 },
 show : function( ) { 
   // ... 
 },
 hide : function( ) {
   // ... 
 },
 update : function( content ) { 
   // ...
 }

};

$.fn.tooltip = function( method ) {

if ( methods[method] ) {
  return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof method === 'object' || ! method ) {
  return methods.init.apply( this, arguments );
} else {
  $.error( 'Method ' \+  method + ' does not exist on jQuery.tooltip' );
}    

};

})( jQuery );
$('#fun').tooltip();
// Some time later...
$('#fun').tooltip('destroy');

7、Data:

关于data方法可以参考官方的文档:http://docs.jquery.com/Data,既是在页面的元素中绑定存储数据。

这里通过编写插件,实现在页面中的每个元素都绑定一些当前的状态或者内容。

(function( $ ){

var methods = {
init : function( options ) {

   return this.each(function(){

     var $this = $(this),
         data = $this.data('tooltip'),
         tooltip = $('<div />', {
           text : $this.attr('title')
         });

     // If the plugin hasn't been initialized yet
     if ( ! data ) {

       /*

Do more setup stuff here
*/

       $(this).data('tooltip', {
           target : $this,
           tooltip : tooltip
       });

     }
   });
 },
 destroy : function( ) {

   return this.each(function(){

     var $this = $(this),
         data = $this.data('tooltip');

     // Namespacing FTW
     $(window).unbind('.tooltip');
     data.tooltip.remove();
     $this.removeData('tooltip');

   })

 },
 reposition : function( ) { // ... },
 show : function( ) { // ... },
 hide : function( ) { // ... },
 update : function( content ) { // ...}

};

$.fn.tooltip = function( method ) {

if ( methods[method] ) {
  return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof method === 'object' || ! method ) {
  return methods.init.apply( this, arguments );
} else {
  $.error( 'Method ' \+  method + ' does not exist on jQuery.tooltip' );
}    

};

})( jQuery );

关于jQuery设计的总结和最佳实践:

编写jQuery插件允许您实现最大的类库,抽象出你认为有用的功能和可重用的代码,可以节省你的时间,使你的开发更加有效。记住当开发您的下一个jQuery插件,可以遵循下面的一个简短的总结:

1、 总是把你的插件放入闭包中:

(function( $ ){ /* plugin goes here */ })( jQuery );

2、 在你的插件直接范围内,不要多余的包裹住this关键字;

3、 除非你是从你的插件中返回一个内在的值,一般都返回你的插件的函数this关键字来维护链接性;

4、 与其传入冗长的参数,不如通过你的插件设置一个默认的参数,通过$.extend()方法进行扩展参数;

5、 不要在一个插件中使用多个命名空间导致jQuery.fn对象变得很杂乱;

6、 总是为你的方法,事件和data创建命名空间。

关于具体的插件开发说明,参考jQuery的官方文档:

http://docs.jquery.com/Plugins/Authoring

欢迎关注我的其它发布渠道

订阅IT宅
内功修炼
Java技术栈
Java架构杂谈是IT宅精品文章公众号,欢迎订阅:
📄 网络基础知识:两万字长文50+张趣图带你领悟网络编程的内功心法 📄 HTTP发展史:三万长文50+趣图带你领悟web编程的内功心法 📄 HTTP/1.1:可扩展,可靠性,请求应答,无状态,明文传输 📄 HTTP/1.1报文详解:Method,URI,URL,消息头,消息体,状态行 📄 HTTP常用请求头大揭秘 📄 HTTPS:网络安全攻坚战 📄 HTTP/2:网络安全传输的快车道 📄 HTTP/3:让传输效率再一次起飞 📄 高性能网络编程:图解Socket核心内幕以及五大IO模型 📄 高性能网络编程:三分钟短文快速了解信号驱动式IO 📄 高性能网络编程:彻底弄懂IO复用 - IO处理杀手锏,带您深入了解select,poll,epoll 📄 高性能网络编程:异步IO:新时代的IO处理利器 📄 高性能网络编程:网络编程范式 - 高性能服务器就这么回事 📄 高性能网络编程:性能追击 - 万字长文30+图揭秘8大主流服务器程序线程模型
📄 Java内存模型:如果有人给你撕逼Java内存模型,就把这些问题甩给他 📄 一文带你彻底理解同步和锁的本质(干货) 📄 AQS与并发包中锁的通用实现 📄 ReentrantLock介绍与使用 📄 ReentrantReadWriteLock介绍与使用 📄 ReentrantLock的Condition原理解析 📄 如何优雅的中断线程 📄 如何优雅的挂起线程 📄 图解几个好玩的并发辅助工具类 📄 图解BlockingQueue阻塞队列
📄 消息队列那么多,为什么建议深入了解下RabbitMQ? 📄 高并发异步解耦利器:RocketMQ究竟强在哪里? 📄 Kafka必知必会18问:30+图带您看透Kafka
📄 洞悉MySQL底层架构:游走在缓冲与磁盘之间 📄 SQL运行内幕:从执行原理看调优的本质 📄 洞悉Redis技术内幕:缓存,数据结构,并发,集群与算法