最近在维护老网站的时候,发现一些jQuery库的使用有些臃肿,并且大部分自定义的js文件很容易污染全局变量,所以想着重写下,虽然jQuery的辉煌时代已经过去了,但是他的思想,依旧灿烂(滚去维护去)
先举个栗子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| ;(function($) { var methods = { init: function(options) { options = $.extend( true, {}, $.fn.myPlugin.defaults, options ); console.log('options', options, this) return this; }, getName: function() { console.log('Name is ', $.fn.myPlugin.defaults.name, '.') }, getAge: function() { console.log('Age is ', $.fn.myPlugin.defaults.age, '.') }, show: function(){ return this.each(function(){ this.style.display == "none" && (this.style.display = '') if (getComputedStyle(this, '').getPropertyValue("display") == "none") this.style.display = defaultDisplay(this.nodeName) }) }, hide: function() { return this.css("display", "none") } };
$.fn.myPlugin = 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.myPlugin.'); } }
$.fn.myPlugin.defaults = { 'name': 'zhangsan', 'age': '20' }; })(jQuery)
$('#testPara').myPlugin()
$('#testPara').myPlugin({ 'name': 'wuwang', 'age': '27' })
$('#testPara').myPlugin('hide') $('#testPara').myPlugin('show')
|
简单易懂,但是五脏俱全,接下来简单说明:
搞定复杂参数列表
首先,我们一般传参如下:
1 2 3
| function foo(a1, a2, a3, a4) { }
foo(1, 2, 3, 4)
|
那如果不传参呐?
就需要如上使用 null 来站位,参数多了,保证你晕。
所以,我们使用 可选哈希参数(options hash),如:
1 2 3 4 5
| foo(1, null, null, 4)
foo(1, { a4: 4 })
|
接着,我们使用 jQuery 的 $.extend() 工具函数合并可选参数,并设置默认值:
1 2 3 4 5 6 7
| function foo (a1, options) { var settings = $.extend({ a2: value2, a3: value3, a4: value4 }, options || {} ); }
|
最后,就有了栗子中形态:
1 2 3 4 5 6
| var settings = $.extend( true, {}, $.fn.myPlugin.defaults, options );
|
这样,就再也不会纠结参数的不传或者多个占位传参,挺好。
实际操作下:先看一个多个参数的:
1 2 3 4 5
| $('#btn').myPlugin({ 'mynewname': 'lisi', 'mynewage': 22 })
|
再看一个:
1 2 3 4 5 6
| $('#btn').myPlugin({ 'name': 'lisi', 'mynewage': 22 })
|
一看就懂,有则覆盖,无则添加,完美。
统一命名空间
由于是jQuery插件,都挂载在 jQuery 对象下,所以恰当命名空间的插件尽可能不与其他插件冲突,甚至是 jQuery 的核心库方法。
比如:
1 2 3 4 5
| (function($) { var defaults = {} var methods = {} $.fn.myPlugin = function(method) {} }(jQuery)
|
允许公开访问默认设置
为了更加的定制化,我们需要暴露默认的设置,这样我们就可以修改设置了。
首先修改 defaults 变量,为了暴露给外部世界,需要把它赋值给 $.fn 属性。并且为了统一命名空间原则,需要把它作为 myPlugin 的属性,如:
1 2 3 4
| $.fn.myPlugin.defaults = { 'name': 'zhangsan', 'age': '20' };
|
接着,当使用默认值来合并参数选项时,在项目中只出现一次,即在 init() 方法里,如:
1 2 3 4 5 6 7 8 9 10 11
| var methods = { init: function(options) { options = $.extend( true, {}, $.fn.myPlugin.defaults, options ); } }
|
这样,当我们在浏览器里直接测试:
1 2 3 4 5 6
| $.fn.myPlugin.defaults.name
$.fn.myPlugin.defaults.name = 'wangwu'
|
维护链式调用性
使用 return this
,可以维护链式调用性。
Array.prototype.slice.call()
Array.prototype.slice.call(arguments)
能将具有length属性的对象转成数组 (arguments.toArray().slice()
)
1 2
| var a={length:2,0:'first',1:'second'}; Array.prototype.slice.call(a);
|
再举个栗子
项目中经常使用轮播图,我们就在前人的基础上,模仿一下吧(你就说是抄的不就行了麽):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
| ; (function ($) { function showPhoto(options, index) { var $photoElement = $(options.photoElement); if (!$photoElement.is(':animated')) { $photoElement.animate({ opacity: 0.5 }, 0).attr( 'src', options.transformer(options.$thumbnails[index].src) ).animate({ opacity: 1 }, 800); options.current = index; } } var methods = { init: function (options) { options = $.extend( true, {}, $.fn.slidePhoto.defaults, options, { current: 0, $thumbnails: this.filter('img'), delay: options.delay >= 1000 ? options.delay : 1000, } );
options.$thumbnails.click(function () { showPhoto(options, options.$thumbnails.index(this)); });
$(options.nextControl + ', ' + options.photoElement).click(function () { var index = (options.current + 1) % options.$thumbnails.length;
showPhoto(options, index); });
$(options.previousControl).click(function () { var index = options.current === 0 ? options.$thumbnails.length - 1 : options.current - 1;
showPhoto(options, index); });
$(options.firstControl).click(function () { showPhoto(options, 0); }).triggerHandler('click');
$(options.lastControl).click(function () { showPhoto(options, options.$thumbnails.length - 1); })
var tick;
function autoPlay() { tick = window.setInterval( function () { $(options.nextControl).triggerHandler('click') }, options.delay); } function mouserStatus(obj) { $(obj).mouseenter(function () { if (tick) { window.clearInterval(tick); } }).mouseleave(autoPlay); }
if (options.autoPlayControl) { autoPlay(); }
mouserStatus(options.photoElement); mouserStatus(options.$thumbnails);
return this; } };
$.fn.slidePhoto = function (method) { if (methods[method]) { return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); } else if ($.type(method) === 'object') { return methods.init.apply(this, arguments); } else { $.error('Method ' + method + ' does not exist on jQuery.slidePhoto'); } };
$.fn.slidePhoto.defaults = { photoElement: 'img.photomatic-photo', transformer: function (name) { return name.replace('thumbnail', 'photo'); }, nextControl: null, previousControl: null, firstControl: null, lastControl: null, autoPlayControl: false, delay: 3000 };
})(jQuery)
|
用法:
1 2 3 4 5 6 7 8 9
| $('#thumbnails-pane img').slidePhoto({ photoElement: '#photo-display', previousControl: '#previous-button', nextControl: '#next-button', firstControl: '#first-button', lastControl: '#last-button', autoPlayControl: true, delay: 3000 });
|
参考: