Zepto是一個輕量級的針對現代高級瀏覽器的JavaScript庫, 它與jquery有着類似的api。 如果你會用jquery,那么你也會用zepto。
昨天聽說了zepto.js,正好最近也比較閑,所以就學習一下這個著名DOM操作庫,由於本人剛接觸這個,但又不想單純的說如何使用,所以本人會按照API順序來說明方法如何使用並試着將對於源碼的理解寫上來;
$():
與jQuery的$()幾乎一樣,但zepto的選擇器是直接使用的原生querySelectorAll(),所以,一些jQuery自定義的選擇器是不支持的,但可以添加selector.js模塊來添加10個(是的,我查了)常用的偽類選擇器;
$()選擇器有五種用法:
$(選擇器,[可選的上下文環境,默認document])
$("#id");/*document.getElementById("id")*/ $("#id time");/*document.querySelectorAll("#id time")*/ $("#id", $("head"));/*如果$('head')只有一個元素,那么就按head[0].querySelectorAll("#id")來取,否則循環$('head')取,返回的都是Zepto對象,可以傳入DOM對象*/ $("<span>hello world</span>");/*將會創建一個span標簽,*/ $("<span>",{text:'hello',id:'span-ele',css:{color:'red'}})/*創建一個id為span-ele,顯示值為hello,紅色的span標簽*/ /*以上為作為選擇器的使用方法*/ $(function () { //do...用過jQuery的應該都知道,這是綁定的DOMContentLoaded 事件 })
當$變量已經存在時,如引用了jQuery,那么zepto的全局對象將不會指向$,但始終指向window.Zepto
接下來瞅瞅內部代碼是如何實現的;
zepto函數最終返回的是一個$符號,$()的調用方式說明了$對象是一個function,所以找到了下圖中的代碼
$函數返回了上圖中的zepto.init()函數的執行結果,接收了兩個參數,第一個是選擇器(selector),第二個是上下文(context),
如果調用時selector為空,則直接返回一個Zepto對象,
如果selector為字符串,先去除兩端空格,然后判斷selector是否為包含html標簽的字符串,
如果是則通過fragment方法生成一個dom對象並返回,
當驗證selector為dom選擇器時,進一步判斷context是否為空,
不為空時將上下文包裝為zepto對象后執行find方法,//這里包裝上下文的作用在於,傳入的上下文也許是一個dom對象,也許是一個zepto對象,而調用.find方法去執行的目的是為了兼容有些zepto對象數組下有多個對象,其實find里邊也是循環調用qsa(zepto封裝的query方法,下邊都會說)
為空時就直接通過document調用query方法了.
當驗證selector為一個Function對象時,就會將該方法綁定至DOMContentLoaded事件,
zepto.isZ函數用來驗證是否為Zepto對象,如果是就直接返回,不做處理,
其余的情況,基本上屬於將基本類型包裝為zepto對象的操作了。但有一點令我不理解的地方是,為何在最后又添加了這么一段重復的邏輯,還希望有知道的同學告訴在下。
最后返回的一個變量經過Zepto的構造函數搖身一變為Zepto對象。
接下來說一下$構造器中用到的一些其他函數;
像通過zepto對象調用的方法,都是可以在其他地方通過$(Zepto).zepto[方法名]調用的, 如 $.zepto.qsa();
而通過$.fn定義的,定制插件也是通過$.fn來完成的,細看代碼會發現這一句
通過$.fn[方法名]定義的為原型的方法;
通過$[方法名]定義的為類方法;
fragment():
該方法用來生成一個dom節點並返回
該方法接收最多三個參數,
第一個為html值,可以只是一個標簽,如(“<span>”)、或一個html片段,如(“<span>hello</span>”);
第二個為一個標識符,用來確定標簽類型,該變量主要用於對表格類元素進行一些特殊的處理,用於生成節點的一個臨時父節點(下邊會說的);
第三個是一些屬性值,是一個json結構的,但要注意為駝峰命名法,因為zepto的精簡,所以不想jQuery那樣的寬容。
首先,方法內部判斷html是否為一個標簽:
如果是,直接生成該標簽;
如果不是,則通過replace方法將自關閉的標簽轉換為普通標簽,tagExpanderRE正則對象內容如下
然后判斷name變量是否為空,如果為空,通過正則取出標簽尖括號內的值。fragmentRE內容如下:
接下來在數組containers中循環查找看該標簽是否為表格類的標簽,如果不是就給一個【*】,【*】的臨時父容器為div。
containers是一個數組,數組中存放的為數個createElement方法:
可以看到這基本上是為了表格而做的- -(本人猜測是因為如果直接將div的innerHTML值賦值為”<tr></tr>“的話會在外側自動生成tbody,table等標簽的。懶得試了,應該是的。。。);
然后就是創建臨時父容器,將html變量直接塞進去。
接下來是一個令我凌亂的方法調用。。。(為何人家就是這么叼???)
通過$.each循環父容器的所有子節點,然后remove該節點,而dom.removeChild()會返回該節點。(卧槽- -)$.each()方法又會返回一個數組,所以間接的就創建了dom節點。(真心感覺讀源碼漲姿勢);
判斷properties是否為一個簡單的Object,方法如下:
然后遍歷該object,將屬性放入dom元素中,那個判斷就不多做解釋了,因為有一些屬性被zepto做成方法了,所以直接調用該方法就可以了,這也是為什么調用$("",{text:'顯示的值'}),可以通過text設置顯示的值,需要做一些樣式處理則可以這樣寫
$("",{css:{color:'red',backgroundColor:'blue'}})/*因為style會有多個,所以css的值必須為一個json*/
完成以后就可以返回該dom元素了。
qsa():
跳過find方法- -以后再說。。。;
qsa(querySelectorAll的縮寫);
方法接收兩個參數,上下文,選擇器;
$()方法中如果不傳入上下文的話,默認是這樣調用的
zepto.qsa(document,selector)
默認將document作為上下文傳入;
作為一個看美劇十句話能聽懂三句的人,表示一眼就能看出maybeID,maybeClass變量的含義- -;
關於simpleSelectorRE這個正則就不貼截圖了,就是個判斷字符串中間是否有空格的。就是說看是不是不包含子選擇器的;
上邊幾個變量都是用來判斷的,下邊是一大串的三元運算符,看着挺暈的,但是聽我解釋完,肯定會明白的(說不定就更暈了);
首先是
確定上下文對象支持getElementById方法,該選擇器不包含子選擇器並且選擇器開頭是個#號,這說明人家要的是個ID:XXX的標簽
如果滿足這種情況,就調用getElementById並將返回結果放入一個數組,這也是為什么獲得jQuery對象就算是通過ID選擇器也會返回一個length為1的數組的原因,如果沒有獲取到該元素,則返回一個空數組;
如果不滿足該條件,則判斷上下文是否為一個標簽節點,文檔對象節點或一個文檔片段節點。如果不是這三個,說明他也不會支持下邊的一些選擇器方法了。直接返回空數組(任性~);
但如果滿足條件了,繼續進行判斷,選擇器為不包含子選擇器的(get√),並且不是通過ID選擇的(get√),而且支持getElementsByClassName的(get√),好了 繼續判斷。。。
mabeyClass(也許是個類選擇器),那么咱們就通過getElementsByClass來取它;
maybeNot(沒有這個變量的),那么就通過getElementByTagName來取;(的確只有這兩種了)
然后這里是不滿足條件的處理
直接通過上下文調用querySelectorAll()方法,這個是支持子選擇器的。(但是jQuery不是這么寫的,至少不全是,因為jQuery還有一些自己的偽類,zepto是沒有的);
關於那個slice.call()只是為了將里邊返回的dom對象放在一個數組里罷了。
先寫那么點吧,快十點了,有點略困;
我是昨天聽說,今天才開始接觸它,如果有哪里寫的不對,還請指出來。謝謝!