首页 > 代码库 > zepto源码解读(二)——zpeto.init()——

zepto源码解读(二)——zpeto.init()——

前面第一节我们大致阐述了zepto的设计结构,看起来东西很多,但是化整为零就没那么繁杂了,一起来看一看,首先我们来看一看zepto源码中可以说是最关键的函数之一zepto.init()。

我们之前说到了$这个api会导致函数zepto返回$这个接口,$呢,是一个函数:

1   // `$` will be the base `Zepto` object. When calling this
2   // function just call `$.zepto.init, which makes the implementation
3   // details of selecting nodes and creating Zepto collections
4   // patchable in plugins.
5   $ = function(selector, context){
6     return zepto.init(selector, context)
7   }

可以看到$函数会返回另一个名为zepto.init()的函数,并且将传入的参数响应传递进去。(这里之所以直接给$赋值而不是var $因为之前已经声明了变量$,所以变量$并不会污染全局)。

那么我们接着来看一看zepto.init()是一个什么样的函数,从字面上看init是初始化的意思。代码如下:

 1 zepto.init = function(selector, context) {
 2     var dom
 3     // If nothing given, return an empty Zepto collection
 4     if (!selector) return zepto.Z()
 5     // Optimize for string selectors
 6     else if (typeof selector == ‘string‘) {
 7       selector = selector.trim()
 8       // If it‘s a html fragment, create nodes from it
 9       // Note: In both Chrome 21 and Firefox 15, DOM error 12
10       // is thrown if the fragment doesn‘t begin with <
11       //如果是<开头 >结尾  基本的HTML代码时
12       if (selector[0] == ‘<‘ && fragmentRE.test(selector))
13       //调用片段生成dom
14         dom = zepto.fragment(selector, RegExp.$1, context), selector = null
15       // If there‘s a context, create a collection on that context first, and select
16       // nodes from there
17       else if (context !== undefined) return $(context).find(selector)
18       // If it‘s a CSS selector, use it to select nodes.
19       //通过css表达式查找元素
20       else dom = zepto.qsa(document, selector)
21     }
22     // If a function is given, call it when the DOM is ready
23     else if (isFunction(selector)) return $(document).ready(selector)
24     // If a Zepto collection is given, just return it
25     else if (zepto.isZ(selector)) return selector
26     else {
27       // normalize array if an array of nodes is given
28       if (isArray(selector)) dom = compact(selector)
29       // Wrap DOM nodes.
30       else if (isObject(selector))
31         dom = [selector], selector = null
32       // If it‘s a html fragment, create nodes from it
33       else if (fragmentRE.test(selector))
34         dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null
35       // If there‘s a context, create a collection on that context first, and select
36       // nodes from there
37       else if (context !== undefined) return $(context).find(selector)
38       // And last but no least, if it‘s a CSS selector, use it to select nodes.
39       else dom = zepto.qsa(document, selector)
40     }
41     // create a new Zepto collection from the nodes found
42     return zepto.Z(dom, selector)
43   }

看起来很复杂对不对,还是用化整为零的思路,我们一步一步分开来看。首先看一下它的结构,用了很多的if else来判断并且处理传入的参数。最终!return zepto.Z()这个函数,可想而知,这个init函数应该是处理参数并且传出两个参数给zepto.Z(),一个名为dom,一个名为selector。至于这个zepto.Z是什么我们先不管,我们来好好看看其中几十行的if...else..是做什么用的。


 

  · 无参数,即$()

1 if (!selector) return zepto.Z()

 

  · selector参数是字符串,例如$(‘p‘) $(‘<div>‘) $(‘#content‘)

 1   else if (typeof selector == ‘string‘) {
 2       selector = selector.trim()
 3       // If it‘s a html fragment, create nodes from it
 4       // Note: In both Chrome 21 and Firefox 15, DOM error 12
 5       // is thrown if the fragment doesn‘t begin with <
 6       //如果是<开头 >结尾  基本的HTML代码时
 7       if (selector[0] == ‘<‘ && fragmentRE.test(selector))
 8       //调用片段生成dom
 9         dom = zepto.fragment(selector, RegExp.$1, context), selector = null
10       // If there‘s a context, create a collection on that context first, and select
11       // nodes from there
12       else if (context !== undefined) return $(context).find(selector)
13       // If it‘s a CSS selector, use it to select nodes.
14       //通过css表达式查找元素
15       else dom = zepto.qsa(document, selector)
16     }

 首先用trim()函数处理selecor参数,清除参数中的空格。

  情况1:参数为<div>这种形式,即是一个html标签的,那么dom变量会被赋值为用这个标签创建的DOM对象,就像dom = document.createElement(‘div‘)差不多。其中涉及到了fragmentREzepto.fragment两个我们尚未了解的东东,此处不要深究,知道这段代码的意思即可。

  情况2,如果第二个参数有值,则先根据第二个参数生成zepto对象,(此处算是一个回调函数)然后再调用.find来获取,例如$(‘.item‘, ‘#content‘)这种用法。find()方法是zepto对象的一个函数。

  情况3,以上两种情况都不是,则调用zepto.qsa来获取数据,后来聊这个方法的具体实现。qsaquerySelectAll的缩写。

  · selector参数是函数,例如$(function(){...})

1  else if (isFunction(selector)) return $(document).ready(selector)

 用到了isFunction()来判断是否为函数以及ready()函数的使用

  · selector本身就是个zepto对象

这种用法比较少,但是也不能避免,例如:

1 var a = $(‘p‘);
2 $(a);  // 这里传入的 a 本身就是个 zepto 对象了。

  · 其他情况

 1    else {
 2       // normalize array if an array of nodes is given
 3       if (isArray(selector)) dom = compact(selector)
 4       // Wrap DOM nodes.
 5       else if (isObject(selector))
 6         dom = [selector], selector = null
 7       // If it‘s a html fragment, create nodes from it
 8       else if (fragmentRE.test(selector))
 9         dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null
10       // If there‘s a context, create a collection on that context first, and select
11       // nodes from there
12       else if (context !== undefined) return $(context).find(selector)
13       // And last but no least, if it‘s a CSS selector, use it to select nodes.
14       else dom = zepto.qsa(document, selector)
15     }

情况1:selector参数是数组,则通过一个compact()处理一下赋值给dom

     if (isArray(selector)) dom = compact(selector)

情况2:selector参数是DOM节点,则将它作为数组赋值给dom。

1      else if (isObject(selector))
2         dom = [selector], selector = null

剩余情况:类似于字符串的操作,只是在输入时没有加入‘‘ "导致不是字符串的情况。

1     else if (fragmentRE.test(selector))
2         dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null
3       // If there‘s a context, create a collection on that context first, and select
4       // nodes from there
5       else if (context !== undefined) return $(context).find(selector)
6       // And last but no least, if it‘s a CSS selector, use it to select nodes.
7       else dom = zepto.qsa(document, selector)

总结

zepto.init函数算是zepto源码中比较复杂的一个函数,一开篇就遇到了个硬骨头。不过我们这里暂且先把那些分叉放在一边,先把大路疏通,然后在慢慢的去一个一个攻破那些分叉。

接下来我们再把init函数的结构梳理一下。

 1 zepto.init = function(selector, context) {
 2     var dom
 3 
 4     // 分情况对dom赋值:
 5     // 1. selector 为空
 6     // 2. selector 是字符串,其中又分好几种情况
 7     // 3. selector 是函数
 8     // 4. 其他情况,例如 selector 是数组、对象等
 9 
10     // create a new Zepto collection from the nodes found
11     return zepto.Z(dom, selector)
12 }

 

zepto源码解读(二)——zpeto.init()——