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