欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Zepto.js之一步步看源码(一)

程序员文章站 2024-03-24 13:33:34
...

最近博主再看zepto.js的源码,zepto.js相较起来比较简短,适合第一次读源码,主要是怕以后忘记,就写下笔记来记录这次源码之旅,总体来说收获还是挺大的。zepto.js就类似于一个迷你的jquery,直接来就仔细来看看这源码怎么回事,我用的版本是Zepto v1.1.6

首先我们看下总体结构

var Zepto = (function() {
    return $
})()

window.Zepto = Zepto
window.$ === undefined && (window.$ = Zepto)

这里是一个自执行函数的返回值赋值给了Zepto,在下面给window下面的Zepto赋值,我们就可以通过Zepto(“#id”)这样来调用,之后的也是赋值给了window下的$,这也是我们最常见的$("#id"),这个表达式是如何计算的呢,当前面是真的时候就返回后面的语句,如果不明白建议看看&&的用法。

我们已经知道总体是怎么回事,那么我们就看看自执行函数里面返回的$是什么

$ = function(selector, context){
    return zepto.init(selector, context)
  }

这里可以看出这个$返回了一个初始化函数,这个初始化函数主要的左右是来判断$("")这里面到底是什么样式,根据不同的样式来分配给不同的方法处理

  zepto.init = function(selector, context) {
    var dom
   //如果是空的话就返回,一会再看zepto.Z()这个函数,其实就是绑定了原型链。
    if (!selector) return zepto.Z()
    else if (typeof selector == 'string') {
     //两种情况$("<p></p>")和$("#id")
      selector = selector.trim()
      // fragmentRE = /^\s*<(\w+|!)[^>]*>/,下面这个就是第一种创建元素的情况
      //这个正则表达式的意思是开头匹配(0,)个回车空格等符号下一个字符是<的之后有有{1,}个字母或数字,或者是!,之后有{0,}个>结尾,这个正则只能匹配出创建元素的情况,但不足以验证其内容的正确性,之后在方法里有验证其内容的正则表达式。zepto.fragment是来验证其内容的。因为很明显<2></2>也符合验证
      if (selector[0] == '<' && fragmentRE.test(selector))
       //下面的方法是来确认表达式,在创建元素,以后再展开吧。这里RegExp.$1为第一个子匹配(表达式中括号的部分)例如<p></p>匹配的就是p这样在fragment中p就是最外层的dom否则默认为div
        dom = zepto.fragment(selector, RegExp.$1, context), selector = null

      // $("#id","li")
      else if (context !== undefined) return $(context).find(selector)
      // $("#id")等我们常用的就在这个方法里
      else dom = zepto.qsa(document, selector)
    }
   //最后都返回一个dom元素节点,是个数组类型的里面装有原型链方法,之后再说
    如果是$(function(){})这个样式的就直接调用ready
    else if (isFunction(selector)) return $(document).ready(selector)
    // 传入的参数本身就已经是 zepto 对象,则直接返回
    else if (zepto.isZ(selector)) return selector
    else {

      // compact函数:过滤掉为null的项
      if (isArray(selector)) dom = compact(selector)

      // 如果传入的是object,直接强制塞进一个数组
      else if (isObject(selector)) dom = [selector], selector = null  
      // fragmentRE = /^\s*<(\w+|!)[^>]*>/ 还是取出第一个标签跟上面的差不多
      else if (fragmentRE.test(selector))
        dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null 
      else if (context !== undefined) return $(context).find(selector)
      else dom = zepto.qsa(document, selector)
    }
    return zepto.Z(dom, selector)
  }

刚才上面的是一次初始化,主要是对于不同的写法干了不同的事,最后返回zepto.Z,我们看看这个函数

zepto.Z = function(dom, selector) {
    dom = dom || []
    //用过原型链的人知道这个__proto__ ,其实在自执行方法返回$的最后还有一段代码 zepto.Z.prototype = $.fn ,这样就是dom.__proto__ = zepto.Z.prototype,就相当于是构造函数实现原型链继承了。虽然自己继承自己,但应该是这么理解的。
    dom.__proto__ = $.fn
    dom.selector = selector || ''
    return dom
  }

最后返回的节点的样子就是

Zepto.js之一步步看源码(一)

,有着各种方法的数组节点,方法都在$.fn中,下次在说说里面的方法,里面方法的写法读起来也收获良多。这次主要说的就是$("")执行这段代码到底发生了什么,深深体会到了代码编写的路漫漫啊。