JackXue程序生涯 2019-06-21
Zepto源码分析(一)核心代码分析
Zepto源码分析(二)奇淫技巧总结
本文只分析核心的部分代码,并且在这部分代码有删减,但是不影响代码的正常运行。
目录
* 用闭包封装Zepto * 开始处理细节 * 正式处理数据(获取选择器选择的DOM) * 正式处理数据(添加DOM到当前实例) * 在实例的原型链上添加方法 * 支持插件扩展 * 验收
用闭包封装Zepto
// 对全局暴露Zepto变量 var Zepto = (function() { // 定义$变量,并将具体细节交给zepto.init处理 $ = function(selector, context){ return zepto.init(selector, context) } // 返回变量 return $ })() // 把Zepto变量挂载在window window.Zepto = Zepto // 当$变量没有被占用的时候,为Zepto设置别名为$ window.$ === undefined && (window.$ = Zepto)
开始处理细节
// 对全局暴露Zepto变量 var Zepto = (function() { // [新增] 初始化zepto变量为对象 var zepto = {} // [新增] 添加初始化方法。当selector参数为空时,则交给zepto.Z()处理 // 当selector为字符串时则把zepto.qsa(document, selector)的值存到dom变量 // 并且交给zepto.Z(dom, selector)处理 zepto.init = function(selector, context) { var dom if (!selector) return zepto.Z() else if (typeof selector == 'string') { dom = zepto.qsa(document, selector) } return zepto.Z(dom, selector) } // 定义$变量,并将具体细节交给zepto.init处理 $ = function(selector, context){ return zepto.init(selector, context) } // 返回变量 return $ })() // 把Zepto变量挂载在window window.Zepto = Zepto // 当$变量没有被占用的时候,为Zepto设置别名为$ window.$ === undefined && (window.$ = Zepto)
正式处理数据(获取选择器选择的DOM)
// 对全局暴露Zepto变量 var Zepto = (function() { // 初始化zepto变量为对象 var zepto = {} // 添加初始化方法。当selector参数为空时,则交给zepto.Z()处理 // 当selector为字符串时则把zepto.qsa(document, selector)的值存到dom变量 // 并且交给zepto.Z(dom, selector)处理 zepto.init = function(selector, context) { var dom if (!selector) return zepto.Z() else if (typeof selector == 'string') { dom = zepto.qsa(document, selector) } return zepto.Z(dom, selector) } // 定义$变量,并将具体细节交给zepto.init处理 $ = function(selector, context){ return zepto.init(selector, context) } // [新增] 使用querySelectorAll(selector)查询DOM zepto.qsa = function(element, selector){ return selector ? element.querySelectorAll(selector) : [] } // 返回变量 return $ })() // 把Zepto变量挂载在window window.Zepto = Zepto // 当$变量没有被占用的时候,为Zepto设置别名为$ window.$ === undefined && (window.$ = Zepto)
正式处理数据(添加DOM到当前实例)
// 对全局暴露Zepto变量 var Zepto = (function() { // 初始化zepto变量为对象 var zepto = {} // [新增] 开始正式处理数据。当dom长度为0则不添加内容, // 否则逐个将dom逐个到当前实例 function Z(dom, selector) { var i, len = dom ? dom.length : 0 for (i = 0; i < len; i++) this[i] = dom[i] this.length = len this.selector = selector || '' } // [新增] 直接返回一个新的构造函数 zepto.Z = function(dom, selector) { return new Z(dom, selector) } // 添加初始化方法。当selector参数为空时,则交给zepto.Z()处理 // 当selector为字符串时则把zepto.qsa(document, selector)的值存到dom变量 // 并且交给zepto.Z(dom, selector)处理 zepto.init = function(selector, context) { var dom if (!selector) return zepto.Z() else if (typeof selector == 'string') { dom = zepto.qsa(document, selector) } return zepto.Z(dom, selector) } // 定义$变量,并将具体细节交给zepto.init处理 $ = function(selector, context){ return zepto.init(selector, context) } // 使用querySelectorAll(selector)查询DOM zepto.qsa = function(element, selector){ return selector ? element.querySelectorAll(selector) : [] } // 返回变量 return $ })() // 把Zepto变量挂载在window window.Zepto = Zepto // 当$变量没有被占用的时候,为Zepto设置别名为$ window.$ === undefined && (window.$ = Zepto)
在实例的原型链上添加方法
// 对全局暴露Zepto变量 var Zepto = (function() { // 初始化zepto变量为对象 var zepto = {}, emptyArray = [] // 开始正式处理数据。当dom长度为0则不添加内容, // 否则逐个将dom逐个到当前实例 function Z(dom, selector) { var i, len = dom ? dom.length : 0 for (i = 0; i < len; i++) this[i] = dom[i] this.length = len this.selector = selector || '' } // 直接返回一个新的构造函数 zepto.Z = function(dom, selector) { return new Z(dom, selector) } // 添加初始化方法。当selector参数为空时,则交给zepto.Z()处理 // 当selector为字符串时则把zepto.qsa(document, selector)的值存到dom变量 // 并且交给zepto.Z(dom, selector)处理 zepto.init = function(selector, context) { var dom if (!selector) return zepto.Z() else if (typeof selector == 'string') { dom = zepto.qsa(document, selector) } return zepto.Z(dom, selector) } // 定义$变量,并将具体细节交给zepto.init处理 $ = function(selector, context){ return zepto.init(selector, context) } // 使用querySelectorAll(selector)查询DOM zepto.qsa = function(element, selector){ return selector ? element.querySelectorAll(selector) : [] } // [新增] 定义each方法 $.each = function(elements, callback){ var i, key if (likeArray(elements)) { for (i = 0; i < elements.length; i++) if (callback.call(elements[i], i, elements[i]) === false) return elements } else { for (key in elements) if (callback.call(elements[key], key, elements[key]) === false) return elements } return elements } // [新增] 定义用于扩展在原型链上的方法 $.fn = { constructor: zepto.Z, length: 0, each: function(callback){ emptyArray.every.call(this, function(el, idx){ return callback.call(el, idx, el) !== false }) return this }, empty: function(){ return this.each(function(){ this.innerHTML = '' }) }, html: function(html){ return 0 in arguments ? this.each(function(idx){ var originHtml = this.innerHTML $(this).empty().append( funcArg(this, html, idx, originHtml) ) }) : (0 in this ? this[0].innerHTML : null) }, test : function(){ return this.each(function(){ console.log('测试链式调用') return this }) } } // [新增] 原型链指向$.fn zepto.Z.prototype = Z.prototype = $.fn // $.zepto指向zepto $.zepto = zepto // 返回变量 return $ })() // 把Zepto变量挂载在window window.Zepto = Zepto // 当$变量没有被占用的时候,为Zepto设置别名为$ window.$ === undefined && (window.$ = Zepto)
支持插件扩展
// 对全局暴露Zepto变量 var Zepto = (function() { // 初始化zepto变量为对象 var zepto = {}, emptyArray = [] // 开始正式处理数据。当dom长度为0则不添加内容, // 否则逐个将dom逐个到当前实例 function Z(dom, selector) { var i, len = dom ? dom.length : 0 for (i = 0; i < len; i++) this[i] = dom[i] this.length = len this.selector = selector || '' } // 直接返回一个新的构造函数 zepto.Z = function(dom, selector) { return new Z(dom, selector) } // 添加初始化方法。当selector参数为空时,则交给zepto.Z()处理 // 当selector为字符串时则把zepto.qsa(document, selector)的值存到dom变量 // 并且交给zepto.Z(dom, selector)处理 zepto.init = function(selector, context) { var dom if (!selector) return zepto.Z() else if (typeof selector == 'string') { dom = zepto.qsa(document, selector) } return zepto.Z(dom, selector) } // 定义$变量,并将具体细节交给zepto.init处理 $ = function(selector, context){ return zepto.init(selector, context) } // [新增] 插件扩展函数 function extend(target, source, deep) { for (key in source) if (source[key] !== undefined) target[key] = source[key] } // [新增] 插件扩展函数 $.extend = function(target){ var deep, args = emptyArray.slice.call(arguments, 1) if (typeof target == 'boolean') { deep = target target = args.shift() } args.forEach(function(arg){ extend(target, arg, deep) }) return target } // 使用querySelectorAll(selector)查询DOM zepto.qsa = function(element, selector){ return selector ? element.querySelectorAll(selector) : [] } // 定义each方法 $.each = function(elements, callback){ var i, key if (likeArray(elements)) { for (i = 0; i < elements.length; i++) if (callback.call(elements[i], i, elements[i]) === false) return elements } else { for (key in elements) if (callback.call(elements[key], key, elements[key]) === false) return elements } return elements } // 定义用于扩展在原型链上的方法 $.fn = { constructor: zepto.Z, length: 0, each: function(callback){ emptyArray.every.call(this, function(el, idx){ return callback.call(el, idx, el) !== false }) return this }, empty: function(){ return this.each(function(){ this.innerHTML = '' }) }, html: function(html){ return 0 in arguments ? this.each(function(idx){ var originHtml = this.innerHTML $(this).empty().append( funcArg(this, html, idx, originHtml) ) }) : (0 in this ? this[0].innerHTML : null) }, test : function(){ return this.each(function(){ console.log('测试链式调用') return this }) } } // 原型链指向$.fn zepto.Z.prototype = Z.prototype = $.fn // $.zepto指向zepto $.zepto = zepto // 返回变量 return $ })() // 把Zepto变量挂载在window window.Zepto = Zepto // 当$变量没有被占用的时候,为Zepto设置别名为$ window.$ === undefined && (window.$ = Zepto)
验收
// 链式调用测试 $('head').test().test() // 测试链式调用\n测试链式调用\n{0: head, length: 1, selector: "head"} $('head').html() // <meta charset="utf-8"><link rel="dns-prefetch" href... // 编写插件测试 ;(function($){ $.extend($.fn, { bw2: function() { return this.html() } }) })(Zepto) $('head').bw2() // <meta charset="utf-8"><link rel="dns-prefetch" href...
欢迎关注前端进阶指南微信公众号:
另外我也创了一个对应的QQ群:660112451,欢迎一起交流。