mass Framework使用了许多手段来一起生成近似方法,从而大大减少代码量,提高维护性。
比如append, prepend, before, after这几个方法,在jQuery2.0,它们是这个样子:
append: function() { return this.domManip(arguments, true, function( elem ) { if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { this.appendChild( elem ); } }); }, prepend: function() { return this.domManip(arguments, true, function( elem ) { if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { this.insertBefore( elem, this.firstChild ); } }); }, before: function() { return this.domManip(arguments, false, function( elem ) { if ( this.parentNode ) { this.parentNode.insertBefore( elem, this ); } }); }, after: function() { return this.domManip(arguments, false, function( elem ) { if ( this.parentNode ) { this.parentNode.insertBefore( elem, this.nextSibling ); } }); },
mass Framework则是这样实现的,连反转方法也一并实现了。
//前导 前置 追加 后放 替换 "append,prepend,before,after,replace".replace($.rword, function(method) { $.fn[method] = function(item) { return manipulate(this, method, item, this.ownerDocument); }; $.fn[method + "To"] = function(item) { $(item, this.ownerDocument)[method](this); return this; }; });
jQuery有三个移除节点的方法,2.0的实现如下:
// keepData is for internal use only--do not document remove: function( selector, keepData ) { var elem, i = 0, l = this.length; for ( ; i < l; i++ ) { elem = this[ i ]; if ( !selector || jQuery.filter( selector, [ elem ] ).length > 0 ) { if ( !keepData && elem.nodeType === 1 ) { jQuery.cleanData( getAll( elem ) ); } if ( elem.parentNode ) { if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { setGlobalEval( getAll( elem, "script" ) ); } elem.parentNode.removeChild( elem ); } } } return this; }, empty: function() { var elem, i = 0, l = this.length; for ( ; i < l; i++ ) { elem = this[ i ]; if ( elem.nodeType === 1 ) { // Prevent memory leaks jQuery.cleanData( getAll( elem, false ) ); // Remove any remaining nodes elem.textContent = ""; } } return this; }, detach: function( selector ) { return this.remove( selector, true ); },
mass Framework则是一起放倒它们。
"remove,empty,detach".replace($.rword, function(method) { $.fn[method] = function() { var isRemove = method !== "empty"; for (var i = 0, node; node = this[i++]; ) { if (node.nodeType === 1) { //移除匹配元素 var array = $.slice(node[TAGS]("*")).concat(isRemove ? node : []); if (method !== "detach") { array.forEach(cleanNode); } } if (isRemove) { if (node.parentNode) { node.parentNode.removeChild(node); } } else { while (node.firstChild) { node.removeChild(node.firstChild); } } } return this; } });
循环生成是艺术,需要深刻了解它们的功能与共同点,然后将特异点组成一个对象,这样方法内的if else就减到最小。
此外动态解析脚本也是个好办法,看mass Framework这段老代码:
//淡入 $.fn.fadeIn = function(duration, complete) { var opts = { duration: duration, complete: complete, effectName: "fadeIn", classRule: ".#{className}{\n\ #{prefix}animation-duration: #{duration};\ #{prefix}animation-name: #{frameName}; \ #{prefix}animation-fill-mode:forwards; \ }", frameRule: "@#{prefix}keyframes #{frameName}{\ to{\ opacity:1;\ }\ }", after: function(node) { node.style.opacity = 1; } } return makeEffect(this, opts); } //淡出 $.fn.fadeOut = function(duration, complete) { var opts = { duration: duration, complete: complete, effectName: "fadeOut", classRule: ".#{className}{\n\ #{prefix}animation-duration: #{duration};\ #{prefix}animation-name: #{frameName}; \ #{prefix}animation-fill-mode:forwards; \ }", frameRule: "@#{prefix}keyframes #{frameName}{\ to{\ opacity:0;\ }\ }", after: function(node) { node.style.opacity = 0; } } return makeEffect(this, opts); }
这两个方法在源码上就只有两处不同,因此后来我改成这样:
$.fn.fadeIn = function(duration, complete) { var opts = { duration: duration, complete: complete, effectName: "fadeIn", classRule: ".#{className}{\n\ #{prefix}animation-duration: #{duration};\ #{prefix}animation-name: #{frameName}; \ #{prefix}animation-fill-mode:forwards; \ }", frameRule: "@#{prefix}keyframes #{frameName}{\ to{\ opacity:1;\ }\ }", after: function(node) { node.style.opacity = 1; } } return makeEffect(this, opts); } //淡出 $.fn.fadeOut = eval("0," + $.fn.fadeIn.toString().replace("1;","0;").replace("faceIn", "fadeOut"))