前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >zepto的构造器$

zepto的构造器$

作者头像
菜的黑人牙膏
发布2019-01-21 16:13:06
5580
发布2019-01-21 16:13:06
举报

在zepto中,通过$来构造对象

代码语言:javascript
复制
$ = function(selector, context){
    return zepto.init(selector, context)
  }

由该函数,实际上,在调用$函数时相当于调用init方法,接下来看init函数:

代码语言:javascript
复制
zepto.init = function(selector, context) {
    var dom
    // If nothing given, return an empty Zepto collection
    //返回一空的zepto对象
    if (!selector) return zepto.Z()
    // Optimize for string selectors
    else if (typeof selector == 'string') {
      //消除空格
      selector = selector.trim()
      //这里根据不同的情况返回dom
      if (selector[0] == '<' && fragmentRE.test(selector))
        dom = zepto.fragment(selector, RegExp.$1, context), selector = null
      // If there's a context, create a collection on that context first, and select
      // nodes from there
      else if (context !== undefined) return $(context).find(selector)
      // If it's a CSS selector, use it to select nodes.
      else dom = zepto.qsa(document, selector)
    }
    // If a function is given, call it when the DOM is ready
    else if (isFunction(selector)) return $(document).ready(selector)
    // If a Zepto collection is given, just return it
    else if (zepto.isZ(selector)) return selector
    else {
      // normalize array if an array of nodes is given
      if (isArray(selector)) dom = compact(selector)
      // Wrap DOM nodes.
      else if (isObject(selector))
        dom = [selector], selector = null
      // If it's a html fragment, create nodes from it
      else if (fragmentRE.test(selector))
        dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null
      // If there's a context, create a collection on that context first, and select
      // nodes from there
      else if (context !== undefined) return $(context).find(selector)
      // And last but no least, if it's a CSS selector, use it to select nodes.
      else dom = zepto.qsa(document, selector)
    }
    // create a new Zepto collection from the nodes found
    return zepto.Z(dom, selector)
  }; 

先来看一下当传入的是一个html标签的字符串时的构造过程:

代码语言:javascript
复制
if (selector[0] == '<' && fragmentRE.test(selector))
        dom = zepto.fragment(selector, RegExp.$1, context), selector = null
fragmentRE = /^\s*<(\w+|!)[^>]*>/;

fragmentRE是一个匹配普通标签<xxx>的表达式,关键是zepto.fragment()函数。

该函数传入三个参数,在这里传入的分别是selector, RegExp.$1, context,RegExp.$1储存的是当前调用的正则表达式匹配的第一个子表达式。即当我们传入<span>时,其值为span,接下来可以看fragment函数。

代码语言:javascript
复制
zepto.fragment = function(html, name, properties) {
    var dom, nodes, container

    // A special case optimization for a single tag
    //创建一个元素
    if (singleTagRE.test(html)) dom = $(document.createElement(RegExp.$1))

    if (!dom) {
      //将html转换为标签,$1$2表示的是匹配的第一个和第二个子表达式
      if (html.replace) html = html.replace(tagExpanderRE, "<$1></$2>")

      if (name === undefined) name = fragmentRE.test(html) && RegExp.$1
      //创建一个name元素  根据是否为表格元素对其进行下一步操作
      if (!(name in containers)) name = '*'

      container = containers[name]
      //将标签插入name元素
      container.innerHTML = '' + html
      //$.each函数最终返回传入的第一个数组参数
      dom = $.each(slice.call(container.childNodes), function(){
        container.removeChild(this)
      })
    }
    if (isPlainObject(properties)) {
      //将dom转成zepto对象
      nodes = $(dom)
      $.each(properties, function(key, value) {
        if (methodAttributes.indexOf(key) > -1) nodes[key](value)
        else nodes.attr(key, value)
      })
    }
    return dom
  }

在这个函数中,有两个正规表达式,分别是tagExpanderRE和singleTagRE

代码语言:javascript
复制
tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig;
singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>|)$/

singleTagRE匹配的是单个的<span></span>诸如此类的标签,而tagExpanderRE匹配的是自闭合标签,如<span/>,但不能是img之类,并将其转成<span><span/>;

从函数中,如果匹配的是单个的html标签,则直接创建该标签并$实例化,将其转变为一个zepto对象,如果匹配的是另一种情况,即将dom转成一个存储这些节点的数组。

然后就是最后一个条件判断了:

代码语言:javascript
复制
if (isPlainObject(properties)) {
      //将dom转成zepto对象
      nodes = $(dom)
      $.each(properties, function(key, value) {
        if (methodAttributes.indexOf(key) > -1) nodes[key](value)
        else nodes.attr(key, value)
      })
    }

先看一下isPlainObject函数,该函数判断是否为一个纯对象:

代码语言:javascript
复制
function isPlainObject(obj) {
    return isObject(obj) && !isWindow(obj) && Object.getPrototypeOf(obj) == Object.prototype
  }    

主要的判断在于Object.getPrototypeOf(obj) == Object.prototype;不同的参数调用getPrototypeOf(obj)返回的值不同:

条件判断里的代码需要注意一点,即将dom转成zepto对象.使其能调用$的attr方法,attr函数留在后面。

重新回到init函数,接下来的都是一些条件判断,其中有一个是选择器函数 即zepto.qsa

代码语言:javascript
复制
zepto.qsa = function(element, selector){
    var found,
        maybeID = selector[0] == '#',
        maybeClass = !maybeID && selector[0] == '.',
        nameOnly = maybeID || maybeClass ? selector.slice(1) : selector, // Ensure that a 1 char tag name still gets checked
        isSimple = simpleSelectorRE.test(nameOnly)
        //条件判断
    return (element.getElementById && isSimple && maybeID) ? // Safari DocumentFragment doesn't have getElementById
      ( (found = element.getElementById(nameOnly)) ? [found] : [] ) :
      (element.nodeType !== 1 && element.nodeType !== 9 && element.nodeType !== 11) ? [] :
      slice.call(
        isSimple && !maybeID && element.getElementsByClassName ? // DocumentFragment doesn't have getElementsByClassName/TagName
          maybeClass ? element.getElementsByClassName(nameOnly) : // If it's simple, it could be a class
          element.getElementsByTagName(selector) : // Or a tag
          element.querySelectorAll(selector) // Or it's not simple, and we need to query all
      )
  }

这个函数就是单纯的选择器函数,init函数最后返回的是zepto.z(dom,selector);

代码语言:javascript
复制
zepto.Z = function(dom, selector) {
    return new Z(dom, selector)
  }
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.prototype = Z.prototype = $.fn

通过中间的构造函数Z,原型链接到$.fn方便调用其方法,最终返回结果对象。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-03-19 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档