Zepto源碼分析(一)核心代碼分析
Zepto源碼分析(二)奇淫技巧總結html
本文只分析核心的部分代碼,而且在這部分代碼有刪減,可是不影響代碼的正常運行。前端
目錄微信
* 用閉包封裝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)
開始處理細節app
// 對全局暴露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)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)
驗收fetch
// 鏈式調用測試 $('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,歡迎一塊兒交流。