Zepto源码分析(一)核心代码分析

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...

欢迎关注前端进阶指南微信公众号:

Zepto源码分析(一)核心代码分析

另外我也创了一个对应的QQ群:660112451,欢迎一起交流。

相关推荐