zepto.init()
1. 首先是第一種情況,selector為空
既然是反向分析,那我們先看看這句話的代碼;
`if (!selector) return zepto.Z()`
這里的返回值為zepto.Z();
那我們繼續(xù)往上找zepto.Z()函數(shù)
java zepto.Z = function(dom, selector) { return new Z(dom, selector) }
這個(gè)函數(shù)仍然擁有一個(gè)返回值,Z函數(shù)的實(shí)例,同樣的道理,我們繼續(xù)去找Z()
;
```java
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 || ''
}
根據(jù)以上代碼可以分析出,當(dāng)沒(méi)有參數(shù)時(shí),會(huì)得到一個(gè)length:0,selector:''
的對(duì)象.
2. 當(dāng)selector為字符串的時(shí)候,又分為三種情況;
同樣的,我們先看看這句話的代碼
```java
else if (typeof selector == 'string') {
selector = selector.trim()
}
```
-
第一種,當(dāng)selector為html片段
if (selector[0] == '<' && fragmentRE.test(selector)) dom = zepto.fragment(selector, RegExp.$1, context), selector = null
-
(1)
fragmentRE.test(selector)
這里的fragmentRE是Zepto函數(shù)在之前定義的一段正則;
//<div>erfwef</div> 取出<div> fragmentRE = /^\s*<(\w+|!)[^>]*>/,
-
(2)
zepto.fragment(selector, RegExp.$1, context)
- RegExp.$1
RegExp.$1為RegExp的一個(gè)屬性,指的是與正則表達(dá)式匹配的第一個(gè) 子匹配(以括號(hào)為標(biāo)志)字符串;
例子:
var r= /^(\d{4})-(\d{1,2})-(\d{1,2})$/; r.exec('1985-10-15'); s1=RegExp.$1; s2=RegExp.$2; s3=RegExp.$3; alert(s1+" "+s2+" "+s3)//結(jié)果為1985 10 15
-
zepto.fragment()
函數(shù)
//對(duì)應(yīng)上面的代碼,這里第一個(gè)參數(shù)是selector,就是我們?cè)趯?xiě)代碼時(shí)的$('xxx')中的xxx, //name為RegExp.$1,即正則匹配的第一個(gè)()里的東西,就是標(biāo)簽元素,例如 div p h1等 zepto.fragment = function(html, name, properties) { var dom, nodes, container // singleTagRE仍為之前定義的變量 //singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, 匹配值如下截圖 //如html傳入值為<p></p>,匹配singleTagRE,則創(chuàng)建<p></p>,并調(diào)用$('<p></p>') if (singleTagRE.test(html)) dom = $(document.createElement(RegExp.$1)) //如果不匹配 if (!dom) { //這是一段修復(fù)代碼,將<div/>之類的不正常的代碼修復(fù)成<div></div>; //具體的下面再講解 if (html.replace) html = html.replace(tagExpanderRE, "<$1></$2>") //如果沒(méi)有標(biāo)簽名,,給他一個(gè)標(biāo)簽,fragmentRE = /^\s*<(\w+|!)[^>]*>/, if (name === undefined) name = fragmentRE.test(html) && RegExp.$1 //containers = {tr': document.createElement('tbody'),tbody': table, 'thead': table, 'tfoot': table,td': tableRow, 'th': tableRow,'*': document.createElement('div')}, //如果name值不在container范圍內(nèi),則標(biāo)簽名為div if (!(name in containers)) name = '*' //創(chuàng)建容器 container = containers[name] //把html片段放入到容器中 container.innerHTML = '' + html //這里調(diào)用了$.each();一會(huì)再詳細(xì)講解,這里是涉及到哪個(gè)函數(shù)我就去解析哪個(gè)函數(shù) //emptyArray = [], slice = emptyArray.slice, //所以這里的slice.call即為Array.prototype.slice.call(),能將具有l(wèi)ength屬性的對(duì)象轉(zhuǎn)成數(shù)組; dom = $.each(slice.call(container.childNodes), function(){ //刪除 container.removeChild(this) }) } //如果properties為對(duì)象 if (isPlainObject(properties)) { //$(dom)將dom轉(zhuǎn)化成zepto對(duì)象元镀;是為了方便調(diào)用其他方法椒楣; nodes = $(dom) $.each(properties, function(key, value) { //methodAttributes = ['val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset'], //如果設(shè)置的key在methodAttributes內(nèi),則直接調(diào)用zepto上的方法拯田; if (methodAttributes.indexOf(key) > -1) nodes[key](value) else nodes.attr(key, value) }) } //<p><span></span></p>返回[p,span] return dom }
- singleTagRE
QQ截圖20170608135118.png -
tagExpanderRE
QQ截圖20170608142535.png - fragmentR
QQ截圖20170608173421.png
- RegExp.$1
-
-
第二種 當(dāng)context有值
else if (context !== undefined) return $(context).find(selector)
這里涉及到一個(gè)方法find,是$.fn中的方法,之后做統(tǒng)一分析;
-
第三種 沒(méi)有context;
else dom = zepto.qsa(document, selector)
zepto.qsa = function(element, selector){ var found, //判斷是不是ID maybeID = selector[0] == '#', //判斷是不是css maybeClass = !maybeID && selector[0] == '.', //看是不是class和id名,如果是,將'#'或者'.'去除,然后賦值給nameOnlt; //否則,直接將值賦值; nameOnly = maybeID || maybeClass ? selector.slice(1) : selector, //simpleSelectorRE = /^[\w-]*$/, //匹配字母數(shù)字下劃線和減號(hào)的組合; isSimple = simpleSelectorRE.test(nameOnly) //如果有內(nèi)置getElementById方法,并且是id名; return (element.getElementById && isSimple && maybeID) ? //則返回element.getElementByID(nameOnly) ( (found = element.getElementById(nameOnly)) ? [found] : [] ) : //反之的話,再做一次判斷 //若element不為元素節(jié)點(diǎn),document,DocumentFragment時(shí);為空, (element.nodeType !== 1 && element.nodeType !== 9 && element.nodeType !== 11) ? [] : //否則,將節(jié)點(diǎn)轉(zhuǎn)換成數(shù)組; slice.call( //這里是一個(gè)三元運(yùn)算符里套著另一個(gè)三元運(yùn)算符; isSimple && !maybeID && element.getElementsByClassName ? //當(dāng)為class,則調(diào)用element.getElementsByClassName(nameOnly) maybeClass ? element.getElementsByClassName(nameOnly) : //否則調(diào)用tagName; element.getElementsByTagName(selector) : //這個(gè)否則是最外層的判斷; element.querySelectorAll(selector) ) }
3. 當(dāng)傳入的值為函數(shù)時(shí),則在dom加載后執(zhí)行它;
else if (isFunction(selector)) return $(document).ready(selector)
4. 如果selector為Z的實(shí)例對(duì)象.則返回他自己;
else if (zepto.isZ(selector)) return selector
5. 最后,又分為5種情況;
-
如果selector為數(shù)組;
// if (isArray(selector)) dom = compact(selector)
這里用到了一個(gè)compact方法;
//這里調(diào)用了一個(gè)filter方法,是在$.fn內(nèi),以后統(tǒng)一分析; //這個(gè)函數(shù)是去除數(shù)組中的null和undefined; function compact(array) { return filter.call(array, function(item){ return item != null }) }
所以當(dāng)為數(shù)組的時(shí)候,去除數(shù)組中的null和undefined;
-
selector為對(duì)象
else if (isObject(selector)) dom = [selector], selector = null
如果selector為對(duì)象,將對(duì)象變?yōu)橐粋€(gè)數(shù)組;
-
selector為html片段;則將其轉(zhuǎn)換成dom
else if (fragmentRE.test(selector)) dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null
-
有context的時(shí)候
else if (context !== undefined) return $(context).find(selector)
-
沒(méi)有context
else dom = zepto.qsa(document, selector)