摘要:我就打算慢慢解析我是怎么寫的,并穿插講解我對(duì)版寫法的理解。其實(shí)源代碼里我都寫有注釋,我也是靠這些注釋回憶我當(dāng)時(shí)是怎么想的。把寫成,那就和的調(diào)用用法一樣。鏈?zhǔn)浇Y(jié)構(gòu)就是在每個(gè)方法結(jié)束時(shí)返回一個(gè)對(duì)象進(jìn)行下一個(gè)方法的操作。
前言
以前大三的時(shí)候?qū)懙囊粋€(gè)小框架,仿jquery鏈?zhǔn)浇Y(jié)構(gòu),純屬練手,大牛勿噴。當(dāng)時(shí)還把JQ的源碼全部打印下來(因?yàn)樵陔娔X上看不方便做筆記),7600+行代碼,300+頁A4紙,對(duì)照著看別人是怎么寫的。還好一個(gè)長我一屆的學(xué)長當(dāng)時(shí)比較閑,我說我想讀JQ代碼,他也沒讀過,就找來上兩屆的學(xué)長以前練手寫的小框架進(jìn)行學(xué)習(xí)。可惜只找到了壓縮混淆后的代碼,對(duì)于一個(gè)渣渣來說,閱讀起來很困難。在他的指點(diǎn)下,我大致了解了原理,并開始著手自己寫。現(xiàn)在陸續(xù)有學(xué)弟找我要這個(gè)代碼。雖然現(xiàn)在覺得寫得一塌糊涂,但是,可能對(duì)于和我當(dāng)時(shí)一樣摸不著邊的人來說,可能會(huì)有幫助。我就打算慢慢解析我是怎么寫的,并穿插講解我對(duì)JQ(2.0版)寫法的理解。其實(shí)源代碼里我都寫有注釋,我也是靠這些注釋回憶我當(dāng)時(shí)是怎么想的。可能會(huì)有很多不好的地方,輕噴~ 罒ω罒
我給庫起名Oct.js,是因?yàn)檫@個(gè)是在企鵝實(shí)習(xí)生應(yīng)聘失敗后為10月校招而寫。紀(jì)念那個(gè)稚嫩的我。
全部代碼,看這里看這里~( ̄▽ ̄)~*
配合使用文檔看代碼更容易理解
為了防止和別的庫的沖突,用閉包把整個(gè)框架安全地保護(hù)好。我們待會(huì)的代碼都寫在里面。這里創(chuàng)建一個(gè)全局變量"window.O",就是在window對(duì)象里加個(gè)O,它等價(jià)于 "Oct",相當(dāng)于jquery、Jquery這樣的別稱,意味著以后用Oct()或O()來進(jìn)行操作。把window.O寫成window.$,那就和JQ的$調(diào)用用法一樣。window.O返回一個(gè)Octobj對(duì)象,這很重要。
(function() { // 創(chuàng)建一個(gè)全局變量"window.O" window.O = Oct = function(selector, root_id, tag) { return new Octobj(selector, root_id, tag); }; // 帥氣地定義一個(gè)版本 Oct.version = "1.0"; })();鏈?zhǔn)浇Y(jié)構(gòu)原理
JQ的流行,我想是因?yàn)樗芊奖惆桑粋€(gè)選擇器就可以接著寫一連串的方法。鏈?zhǔn)浇Y(jié)構(gòu)就是在每個(gè)方法結(jié)束時(shí)返回一個(gè)對(duì)象進(jìn)行下一個(gè)方法的操作。后面會(huì)通過代碼說明
選擇器選擇器非常重要。JQ特別把選擇器部分剝離出一個(gè)庫sizzle.js。現(xiàn)在的JQ內(nèi)部也是調(diào)用JQ里面的sizzle。“選擇器”三個(gè)字寫得簡單,代碼寫起來就很有學(xué)問,sizzle.js這種高大上的我就不說了。我這里簡單實(shí)現(xiàn)一些功能:選擇class/id/標(biāo)簽。
首先,把上面的Octobj對(duì)象骨架搭建起來。包含selector, root_id, tag三個(gè)參數(shù)。selector就是你想要找的東西,root_id是你想要找的東西的上級(jí)的id,tag是你要指定返回某種標(biāo)簽。
var Octobj = function(selector, root_id, tag) { };
定義一些參數(shù)
// args: 存儲(chǔ)root_id的子標(biāo)簽 // type: 類型標(biāo)記,id("#"), class(".") 或者 tag("&。 tag也加標(biāo)記是為了代碼方便 // eles: 臨時(shí)的,存儲(chǔ)`selector`變量里"# . &"標(biāo)記后面的字符串 // selector_exp: 用來匹配標(biāo)簽的正則規(guī)則 var agrs, type, eles; var selector_exp = /^(?:#(w-_)+|.(w-_)+|(w)+)$/; // this.elements: 存儲(chǔ)函數(shù)結(jié)束后返回對(duì)象 this.elements = []; // 防止以下情況: $(""), $(null), $(undefined), $(false) if (!selector) { return this; }
接下來處理有沒有指定root_id、tag的情況,
if (root_id) { root_id = typeof root_id == "string" ? document.getElementById(root_id) : root_id; } else { root_id = document.body; } tag = tag || "*"; if (tag !== "*") { tag = tag.slice(1); }
進(jìn)入核心部分。分兩種情況,能支持querySelector()方法的“高級(jí)”瀏覽器和不能支持的“低端”瀏覽器。先是能支持querySelector的,就很簡單了:
if (document.querySelectorAll) { // 因?yàn)槲矣?&"符號(hào)來標(biāo)記標(biāo)簽 ,所以要用"replace()"去掉"&" var node_list = document.querySelectorAll(selector.replace("&", "")) for (var i in node_list) { if (node_list[i].tagName !== undefined) { // 把符合要求的元素存入`this.elements` this.elements.push(node_list[i]); } } }
不能支持querySelector的,先來設(shè)置一些參數(shù):
// 處理類似JQ $(".a .b")的情況 selector = selector.replace(/^s+/, "").split(/s+/); // 如果不指明 "root_id" 和 "tag", "args" 就存儲(chǔ)所有的標(biāo)簽 args = root_id.getElementsByTagName(tag); // 通過符號(hào)標(biāo)記判斷是class/id/tag type = selector[0].charAt(0); // 所要選取的目標(biāo)的字符串 eles = selector[0].slice(1);
處理選擇class的情況。有文章指出for in的效率不高,我本來是用for處理的,但是出現(xiàn)問題,因?yàn)闀?huì)把方法一起選進(jìn)來。JQ用了for in,感覺有了標(biāo)桿,我就全部改用for in了。
if (type === ".") { // 查找每個(gè)標(biāo)簽中有className,提取處理進(jìn)行匹配 for (var i in args) { if(args[i].className) { // className 可能不止一個(gè), 通過空格進(jìn)行分割 var r = args[i].className.split(/s+/); for (var j in r) { if (r[j] === eles) { this.elements.push(args[i]); } } } } }
處理選擇id的情況:
else if (type === "#") { for (var i in args) { if(args[i].id) { var r = args[i].id.split(/s+/); for (var j in r) { if (r[j] === eles) { this.elements.push(args[i]); } } } } }
處理選擇標(biāo)簽的情況:
else if (type === "&") { for (var i in args) { // 你可以"console.log(args[i]);" 可以看到最后一個(gè)是"length" ,沒有"tagName",所以要排除這個(gè)情況,否則會(huì)報(bào)錯(cuò) if (i !== "length" && typeof args[i] !== "function") { // "args[i].tagName" 在瀏覽器的屬性里是用大寫的,為了符合我的習(xí)慣,改用小寫進(jìn)行判斷 if (args[i].tagName.toLowerCase() === eles.toLowerCase()) { this.elements.push(args[i]); } } } }
基礎(chǔ)選擇器部分完成了,別忘了最后一句,返回找到的元素,給下一個(gè)方法進(jìn)行操作:
return this;
全部代碼
用法舉例1.通過 id 選擇.
O("#buddy")
2.通過 class 選擇.
Oct(".buddy")
3.選擇所有 div.
O("&div") // also O("&Div"), O("&DIV")
4.選擇 .buddy 里的
.
O(".buddy", null, "&p")
5.選擇#dad下的.buddy
O(".buddy", "#dad")
Laker"s blog
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/91446.html
摘要:標(biāo)簽不區(qū)分大小寫,但推薦小寫。標(biāo)簽可以嵌套,但不能交叉嵌套。標(biāo)簽也稱為元素。比如行內(nèi)標(biāo)簽亦可成行內(nèi)元素。 ??HTML必備知識(shí)詳解?? 第一部分:HTML框架簡介...
摘要:至于我為何要這么做,請(qǐng)聽閏土娓娓道來。那么接下來,正文從這開始熟悉閏土的朋友都知道,我是從時(shí)代過來的前端,在剛接觸和這類框架的時(shí)候,完全可以用一臉懵逼來形容我,最為貼切。作者閏土少年出處本博客的文章如無特殊說明,均為原創(chuàng),轉(zhuǎn)載請(qǐng)注明出處。 showImg(https://segmentfault.com/img/bVZjKW?w=670&h=442); 前言 在我動(dòng)筆寫這篇文章的時(shí)候,...
摘要:相關(guān)頻道最后的坦白最后我得承認(rèn)這一次我又標(biāo)題黨了無非是想吸引更多前端初學(xué)者進(jìn)來,希望大家都能少走一些彎路,也希望那些從零開始自學(xué)前端的同學(xué)更有勇氣去面對(duì)自己的選擇。 我是怎么走上前端開發(fā)這條路? 首先,我是個(gè)文科生,大學(xué)里只學(xué)過vb,覺得計(jì)算機(jī)編程這東西太玄乎,不是我玩得轉(zhuǎn)的。 后來機(jī)緣巧合去做了一家互聯(lián)網(wǎng)創(chuàng)業(yè)公司的HR,閱了上千份程序員的簡歷,面了上百個(gè)不同水平不同領(lǐng)域的程序員。跟程...
摘要:書籍如下面向?qū)ο缶幊讨改希L(fēng)格輕松易懂,比較適合初學(xué)者,原型那塊兒講得透徹,種繼承方式呢。還有另一件事情是,比如發(fā)現(xiàn)自己某個(gè)知識(shí)點(diǎn)不太清楚,可以單獨(dú)去百度。 作者:小不了鏈接:https://zhuanlan.zhihu.com/p/...來源:知乎著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。 鑒于時(shí)不時(shí),有同學(xué)私信問我(老姚,下同)怎么學(xué)前端的問題。這里統(tǒng)一回...
閱讀 2063·2021-11-11 16:55
閱讀 1398·2021-09-28 09:36
閱讀 1046·2019-08-29 15:21
閱讀 1576·2019-08-29 14:10
閱讀 2762·2019-08-29 14:08
閱讀 1635·2019-08-29 12:31
閱讀 3250·2019-08-29 12:31
閱讀 981·2019-08-26 16:47