扩展 jQuery 有两种形式:
直接定义在 $ 上的实用函数
操作 jQuery 包装集的方法
1. jQuery插件开发指南
1.1 为文件和函数命名
为文件名添加jquery前缀
前缀后面是插件的名称
包含插件的主版本号和次版本号(可选项)
以.js结束
1.2 当心 $
(function($){
//
// 插件定义
//
})(jQuery);
1.3 简化参数列表
使用 options 散列值。
例如:complex(valueA, {p7: valueB});
complex(valueA, {
p3: valueC,
p4: valueD,
p7: valueB
});
简化后的函数签名:complex(p1, options)
在函数中,使用 $.extend() 将这些选项与默认值合并:
function complex(p1, options) {
var settings = $.extend({
option1: defaultValue1,
option2: defaultValue2,
option3: defaultValue3
}, options || {});
// 函数其他部分
}
2. 编写自定义实用函数
实用函数是定义为 jQuery($)属性的函数,它不是为了操作DOM元素。
$.say = function(what) { alert('I say ' + what); };
也可以:jQuery.say = function(what) { alert('I say ' + what); };
最安全的写法:
(function($){
$.say = function(what) { alert('I say ' + what); };
})(jQuery);
2.1 创建数据操作的实用函数
创建这样的实用函数:$.toFixedWidth(value, length, fill)
(function($) {
$.toFixedWidth = function(value, length, fill) {
var result = (value || '').toString();
fill = fill || '0';
var padding = length - result.length;
if (padding < 0) {
result = result.substr(-padding);
} else {
for (var n = 0; n < padding; n++)
result = fill + result;
}
return result;
};
})(jQuery);
为实用函数添加命名空间:
$.jQiaDataFormatter = {};
$.jQiaDataFormatter.toFixedWidth = function(value, length, fill){...};
2.2 编写日期格式器
语法:$.formatDate(date, pattern)
yyyy
yy
MMMM
MMM
MM
M
dd
d
EEEE
EEE
a
HH
H
hh
h
mm
m
ss
s
S
(function($){ $.formatDate = function(date,pattern) { var result = []; while (pattern.length>0) { $.formatDate.patternParts.lastIndex = 0; var matched = $.formatDate.patternParts.exec(pattern); if (matched) { result.push($.formatDate.patternValue[matched[0]].call(this,date)); pattern = pattern.slice(matched[0].length); } else { result.push(pattern.charAt(0)); pattern = pattern.slice(1); } } return result.join(''); }; $.formatDate.patternParts = /^(yy(yy)?|M(M(M(M)?)?)?|d(d)?|EEE(E)?|a|H(H)?|h(h)?|m(m)?|s(s)?|S)/; $.formatDate.monthNames = [ 'January','February','March','April','May','June','July', 'August','September','October','November','December' ]; $.formatDate.dayNames = [ 'Sunday','Monday','Tuesday','Wednesday','Thursday','Friday', 'Saturday' ]; $.formatDate.patternValue = { yy: function(date) { return $.toFixedWidth(date.getFullYear(),2); }, yyyy: function(date) { return date.getFullYear().toString(); }, MMMM: function(date) { return $.formatDate.monthNames[date.getMonth()]; }, MMM: function(date) { return $.formatDate.monthNames[date.getMonth()].substr(0,3); }, MM: function(date) { return $.toFixedWidth(date.getMonth()+1,2); }, M: function(date) { return date.getMonth()+1; }, dd: function(date) { return $.toFixedWidth(date.getDate(),2); }, d: function(date) { return date.getDate(); }, EEEE: function(date) { return $.formatDate.dayNames[date.getDay()]; }, EEE: function(date) { return $.formatDate.dayNames[date.getDay()].substr(0,3); }, HH: function(date) { return $.toFixedWidth(date.getHours(),2); }, H: function(date) { return date.getHours(); }, hh: function(date) { var hours = date.getHours(); return $.toFixedWidth(hours>12 ? hours - 12 : hours,2); }, h: function(date) { return date.getHours()%12; }, mm: function(date) { return $.toFixedWidth(date.getMinutes(),2); }, m: function(date) { return date.getMinutes(); }, ss: function(date) { return $.toFixedWidth(date.getSeconds(),2); }, s: function(date) { return date.getSeconds(); }, S: function(date) { return $.toFixedWidth(date.getMilliseconds(),3); }, a: function(date) { return date.getHours() < 12 ? 'AM' : 'PM'; } }; $.toFixedWidth = function(value,length,fill) { var result = (value || '').toString(); fill = fill || '0'; var padding = length - result.length; if (padding < 0) { result = result.substr(-padding); } else { for (var n = 0; n < padding; n++) result = fill + result; } return result; };})(jQuery);
3. 添加新的包装器方法
创建模式:$.fn.wrapperFunctionName = function(params){ fucntion-body };
示例:
(function($){
$.fn.makeItblue = function() {
return this.css('color', 'blue');
};
})(jQuery);
注意:$.fn 是对象内部 prototype 属性的别名。
警告:包装器主体部分中的函数上下文(this)指向包装集,但是当在这个函数内声明内联函数时,每一个内联函数都有其自己的函数上下文。这时使用 this 要小心!
在定义新的包装器方法时还有一个非常重要的原则:除非要返回特定的值,否则函数应该总是将包装集作为其返回值。这允许新方法参与到任何 jQuery 方法链中。
单独处理每个包装元素的模式:
(function($) {
$.fn.someNewMethod = function() {
return this.each(function() {
//
// this 指向单个的DOM元素
//
});
};
})(jQuery);
示例:
(function($) {
$.fn.makeItBlueOrRed = function() {
return this.each(function() {
$(this).css('color', $(this).is('[id]') ? 'blue' : 'red');
});
};
})(jQuery);
这个例子只是用来演示,实际上可以简化为:
(function($) {
$.fn.makeItBlueOrRed = function() {
return this.css('color', function() {
return $(this).is('[id]') ? 'blue' : 'red');
});
};
})(jQuery);
3.1 在包装器方法中应用多个操作
示例:setReadOnly(state) state为true,将文字不透明度设置为0.5表示只读。
(function($){
$.fn.setReadOnly = function(readonly) {
return this.filter('input:text')
.attr('readOnly', readonly)
.css('opacity', readonly ? 0.5 : 1.0)
.end();
};
})(jQuery);
3.2 保留在包装器方法里的状态
方法语法:photomatic(options)
options:
firstControl
lastControl
nextControl
photoElement
playControl
previousControl
transformer
delay - 毫秒,默认3000
用法:
$('#thumbnailsPane img').photomatic({
photoElement: '#photoDisplay',
previousControl: '#previousButton',
nextControl: '#nextButton',
firstControl: '#firstButton',
lastControl: '#lastButton',
playControl: '#playButton',
delay: 1000
});
实现:
(function($){ $.fn.photomatic = function(options) { var settings = $.extend({ photoElement: 'img.photomaticPhoto', transformer: function(name) { return name.replace(/thumbnail/,'photo'); }, nextControl: null, previousControl: null, firstControl: null, lastControl: null, playControl: null, delay: 3000 },options||{}); function showPhoto(index) { $(settings.photoElement) .attr('src', settings.transformer(settings.thumbnails$[index].src)); settings.current = index; } settings.current = 0; settings.thumbnails$ = this.filter('img'); settings.thumbnails$ .each( function(n){ $(this).data('photomatic-index',n); } ) .click(function(){ showPhoto($(this).data('photomatic-index')); }); $(settings.photoElement) .attr('title','Click for next photo') .css('cursor','pointer') .click(function(){ showPhoto((settings.current+1) % settings.thumbnails$.length); }); $(settings.nextControl).click(function(){ showPhoto((settings.current+1) % settings.thumbnails$.length); }); $(settings.previousControl).click(function(){ showPhoto((settings.thumbnails$.length+settings.current-1) % settings.thumbnails$.length); }); $(settings.firstControl).click(function(){ showPhoto(0); }); $(settings.lastControl).click(function(){ showPhoto(settings.thumbnails$.length-1); }); $(settings.playControl).toggle( function(event){ settings.tick = window.setInterval( function(){ $(settings.nextControl).triggerHandler('click'); }, settings.delay); $(event.target).addClass('photomatic-playing'); $(settings.nextControl).click(); }, function(event){ window.clearInterval(settings.tick); $(event.target).removeClass('photomatic-playing'); }); showPhoto(0); return this; };})(jQuery);