zoukankan      html  css  js  c++  java
  • zepto学习之路--核心函数$()的实现

      $()可以说是jquery的精华了,为dom操作带来了极大的灵活和方便。zepto号称“移动版的jquery”,那么它是怎么来实现这个核心函数呢?我们来详细探讨下。

    1、首先,我们看下zepto中它是怎么定义的:

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

      这里很明显,如果你试图通过S(“”)来获取一个dom元素,zept会将其封装为一个zepto对象返回给你,那么zepto.init是如何实现的呢?

    2、zepto.init

    zepto.init = function(selector, context) {
        // If nothing given, return an empty Zepto collection
        if (!selector) return zepto.Z() //没有参数,返回空数组
        //如果selector是个函数,则在DOM ready的时候执行它
        else if (isFunction(selector)) return $(document).ready(selector)
        //如果selector是一个zepto.Z实例,则直接返回它自己
        else if (zepto.isZ(selector)) return selector
        else {
          var dom
          //如果selector是一个数组,则将其里面的null,undefined去掉
          if (isArray(selector)) dom = compact(selector)
          //如果selector是个对象,注意DOM节点的typeof值也是object,所以在里面还要再进行一次判断
          else if (isObject(selector))
          //如果是申明的对象,如{}, 则将selector属性copy到一个新对象,并将结果放入数组
          //如果是该对象是DOM,则直接放到数组中
          dom = [isPlainObject(selector) ? $.extend({}, selector) : selector], selector = null
          //如果selector是一段HTML代码片断,则将其转换成DOM节点
          else if (fragmentRE.test(selector)) dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null
          //如果存在上下文context,则在上下文中查找selector,此时的selector为普通的CSS选择器
          else if (context !== undefined) return $(context).find(selector)
          //如果没有给定上下文,则在document中查找selector,此时的selector为普通的CSS选择器
          else dom = zepto.qsa(document, selector)
          //最后将查询结果转换成zepto集合
          return zepto.Z(dom, selector)
        }
      }
    

      在这里zepto.innit函数根据输入参数的情况来进行不同的操作,如果你输入的参数是标准的(selector,context)的形式,其会调用zepto.qsa也就是dom查询函数,最后最后将得到的元素数组用zepto.z()函数包装成zepto对象数组返回。所以这个函数的包括两个过程:一、查找生成满足条件dom元素数组;二、将dom元素包装成zepto对象,这样返回的对象就具有了zepto的方法。ok,我们继续分解这两个过程:

    3、zepto.qua()

      

    zepto.qsa = function(element, selector) {
        var found
        //当element为document,且selector为ID选择器时
        return (isDocument(element) && idSelectorRE.test(selector)) ?
        //直接返回document.getElementById,RegExp.$1为ID的值,当没有找节点时返回[]
        ((found = element.getElementById(RegExp.$1)) ? [found] : []) :
        //当element不为元素节点或者document时,返回[]
        (element.nodeType !== 1 && element.nodeType !== 9) ? [] :
        //否则将获取到的结果转成数组并返回
        slice.call(
        //如果selector是标签名,直接调用getElementsByClassName
        classSelectorRE.test(selector) ? element.getElementsByClassName(RegExp.$1) :
        //如果selector是标签名,直接调用getElementsByTagName
        tagSelectorRE.test(selector) ? element.getElementsByTagName(selector) :
        //否则调用querySelectorAll
        element.querySelectorAll(selector))
      }
    

      ok,你没看错,这就是zepto的核心dom查找函数,其思想是先用正则表达式判断selector的类型,然后调用相应的方法。对于不是单一类型的选择符,最后用querySelectorAll()函数来进行查询,并且用slice将得到的元素集合转化为数组。这里因为面向移动端,所以也没有考虑queryselectall的兼容性。在这里附带一点,在ie6,7中是不支持queryselectorall方法的,有人提出了一种补充的方法来解决兼容性:

    if (!document.querySelectorAll) {
        document.querySelectorAll = function (selectors) {
            var style = document.createElement('style'), elements = [], element;
            document.documentElement.firstChild.appendChild(style);
            document._qsa = [];
    
            style.styleSheet.cssText = selectors + '{x-qsa:expression(document._qsa && document._qsa.push(this))}';
            window.scrollBy(0, 0);
            style.parentNode.removeChild(style);
    
            while (document._qsa.length) {
                element = document._qsa.shift();
                element.style.removeAttribute('x-qsa');
                elements.push(element);
            }
            document._qsa = null;
            return elements;
        };
    }
    
    if (!document.querySelector) {
        document.querySelector = function (selectors) {
            var elements = document.querySelectorAll(selectors);
            return (elements.length) ? elements[0] : null;
        };
    }
    
    // 用于在IE6和IE7浏览器中,支持Element.querySelectorAll方法
    var qsaWorker = (function () {
        var idAllocator = 10000;
    
        function qsaWorkerShim(element, selector) {
            var needsID = element.id === "";
            if (needsID) {
                ++idAllocator;
                element.id = "__qsa" + idAllocator;
            }
            try {
                return document.querySelectorAll("#" + element.id + " " + selector);
            }
            finally {
                if (needsID) {
                    element.id = "";
                }
            }
        }
    
        function qsaWorkerWrap(element, selector) {
            return element.querySelectorAll(selector);
        }
    
        // Return the one this browser wants to use
        return document.createElement('div').querySelectorAll ? qsaWorkerWrap : qsaWorkerShim;
    })();
    

      4、zepto.z()

      在找到dom元素数组后,剩下的就是将其封装成zepto对像。

    zepto.Z = function(dom, selector) {
        dom = dom || []
        dom.__proto__ = $.fn //通过给dom设置__proto__属性指向$.fn来达到继承$.fn上所有方法的目的
        dom.selector = selector || ''
        return dom
      }
    

      没错,这个Z函数就是包装函数,短小而强悍。zepto处理的方法及其剪短,通过将$.fn赋给dom的__proto__属性,来继承fn的属性,这也就意味着这一步后,你同过$()方法得到的元素都拥有了fn中的方法。进而链式调用也就实现了。。。

  • 相关阅读:
    野指针防范
    Linuxgate.so.1的含义[ZZ]
    malloc hook
    用PDF补丁丁一分钟批量删除PDF文档的第一页和最后一页
    PDF 补丁丁 0.4 测试版已经上线
    生活小百科:实用的生活保健小窍门,60则!....
    Pascal Analyzer 4 代码分析使用简要说明
    大数法则
    make: *** No rule to make target `all'. Stop.
    界面动态配置:持久化反持久化
  • 原文地址:https://www.cnblogs.com/dunken/p/4443518.html
Copyright © 2011-2022 走看看