摘要:如此循環(huán),直到結(jié)束如果循環(huán)結(jié)束之后,比字符串的長度要小,那說明后面還有文本匹配失敗了。
BiuJS
BiuJS是一個輕巧的mvvm框架編譯
它實現(xiàn)了數(shù)據(jù)的雙向綁定
并提供一些基本的指令幫助你提升效率,比如$for,$model,$if,$click,$style
是的,如你所見,以$開頭的指令是它的獨特標(biāo)識
1000行左右的代碼量,讓應(yīng)用的開發(fā)和加載biu的一瞬完成
BiuJS倉庫: https://github.com/veedrin/biu
現(xiàn)在我們來看看視圖
let app = new Biu({ mount: "#app", data: {}, action: {} });
這里傳進來的mount是BiuJS的掛載點,它的意思是說:id="app"所在的元素以及后代元素現(xiàn)在被BiuJS接管了
這片區(qū)域就是我們要編譯的范圍
function Compiler(mount, vm) { this.vm = vm; if (mount) { let fragment = this.eleToFragment(mount); this.compile(fragment); mount.appendChild(fragment); } } Compiler.prototype.eleToFragment = function(ele) { let fragment = document.createDocumentFragment(); let child; while(child = ele.firstChild) { fragment.appendChild(child); } return fragment; };
要給DOM做手術(shù),我們就要先把它抽出來,暫時裝在文檔碎片里
編譯完以后,再整體的插回原來的位置
胡子模板,也叫文本插值,是作為文本節(jié)點,而指令是屬于元素節(jié)點的,所以我們要分開編譯
let regBlank = /^s+$/; Compiler.prototype.compile = function(ele) { let self = this; if (ele.childNodes && ele.childNodes.length) { Array.from(ele.childNodes).forEach((child) => { if (child.nodeType === 3 && !regBlank.test(child.textContent)) { self.compileText(child); } else if (child.nodeType === 1) { self.compileElement(child); } self.compile(child); }); } };
我們知道文本節(jié)點會把元素之間的空隙也算進去,編譯它毫無意義,所以排除掉
編譯文本我們先講文本編譯,指令編譯會多帶帶抽幾個出來在后面文章講
好,現(xiàn)在假設(shè)我們捕捉到了一個文本節(jié)點
跟上面一樣,編譯就是一個分解組裝的過程,所以也要用一個文檔碎片緩存起來
有一個知識點,exec方法作用在加了全局匹配修飾符的正則表達(dá)式上時,需要多次匹配才能獲得所有的結(jié)果。正則表達(dá)式的lastIndex屬性就是用來標(biāo)記匹配到哪里了
舉個例子
let str = "I am biu, I do biu things, I appreciate biu things."; let reg = /biu/g; // 0 console.log(reg.lastIndex); // ["biu", index: 5, input: "I am biu, I do biu things, I appreciate biu things."] 8 console.log(reg.exec(str), reg.lastIndex); // ["biu", index: 15, input: "I am biu, I do biu things, I appreciate biu things."] 18 console.log(reg.exec(str), reg.lastIndex); // ["biu", index: 40, input: "I am biu, I do biu things, I appreciate biu things."] 43 console.log(reg.exec(str), reg.lastIndex); // null 0 console.log(reg.exec(str), reg.lastIndex);
一個文本節(jié)點里可能有好幾個胡子模板
我叫{{name}},我今年{{age}}歲了
所以我們要用一個循環(huán)把它們?nèi)珦赋鰜?/p>
let regMustache = /{{(.*?)}}/g; let content = ele.textContent.trim(); let fragment = document.createDocumentFragment(); let i = 0; let match; let text; while (match = regMustache.exec(content)) { if (i < match.index) { text = content.slice(i, match.index); let element = document.createTextNode(text); fragment.appendChild(element); } i = regMustache.lastIndex; let exp = match[1]; let element = document.createTextNode(""); let result = execChain(exp, this.vm); element.textContent = result; fragment.appendChild(element); new Watcher(exp, this.vm, (newValue) => { element.textContent = newValue; }); } if (i < content.length) { text = content.slice(i); let element = document.createTextNode(text); fragment.appendChild(element); }
如果match.index不是從0開始的,那就說明前面還有文本是匹配失敗了。雖然匹配失敗,我們還是要原樣把它組裝回去吧。這就是第一部分
第二部分就是匹配成功了,我們要把它其中的表達(dá)式摳出來,轉(zhuǎn)成實際的值,再組裝回去。如此循環(huán),直到結(jié)束
如果while循環(huán)結(jié)束之后,match.index比字符串的長度要小,那說明后面還有文本匹配失敗了。一樣的,原樣把它組裝回去
經(jīng)過這三部分,一個文本節(jié)點就算編譯完成了
表達(dá)式求值因為BiuJS的表達(dá)式并不是真正的表達(dá)式,它不支持計算(或者暫時不支持)
所以表達(dá)式求值實際上指的是:求嵌套對象的屬性的值
{{aa.bb.cc}}或者{{aa["bb"].cc}}或者{{aa["bb"]["cc"]}}{{aa + 3}}
先把這些對象或?qū)傩悦槿〕鰜恚诺揭粋€數(shù)組里面
然后再用遞歸一步一步的向里求值,就可以獲得aa.bb.cc的值了
let regChain = /[[].""]/; function splitChain(exp) { let arr = exp.split(regChain); if (arr.length === 1) { return arr; } let chain = []; for (let i = 0, len = arr.length; i < len; i++) { arr[i] && chain.push(arr[i]); } return chain; } function execChain(exp, vm) { let chain = splitChain(exp); let temp; function recursion(obj, i) { let prop = obj[chain[i]]; if (prop !== undefined) { temp = prop; i < chain.length && recursion(temp, i + 1); } } recursion(vm.$data, 0); return temp; }
action方法集合沒有嵌套,所以直接取就可以了
這就是表達(dá)式轉(zhuǎn)成實際的值的過程
訂閱器上面的文本編譯部分有一個new Watcher(),還有印象嗎?
這就是傳說中的訂閱器
這個訂閱器的作用是什么呢?其實也很簡單
把模板里摳出來的表達(dá)式、BiuJS的實例、還有回調(diào)函數(shù)打包在一起
通過觸發(fā)getter將包裹送到訂閱數(shù)組里面
function Watcher(exp, vm, cb) { this.exp = exp; this.vm = vm; this.update = cb; this.trigger(); } Watcher.prototype.trigger = function() { Dep.target = this; execChain(this.exp, this.vm); Dep.target = null; };
打包物品,送到目的地,這不就是快遞公司么
之前的文章我們還埋了一個點:“訂閱者是什么時候掛到Dep.target上的?”
就是在這個時候掛上去的
不過要馬上清空,因為它其實挺忙的,要接不少客
寫在后面以上就是文本編譯的過程
歡迎到BiuJS倉庫: https://github.com/veedrin/biu了解詳情
更歡迎Star和Fork
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/92286.html
摘要:是一個輕巧的框架它實現(xiàn)了數(shù)據(jù)的雙向綁定并提供一些基本的指令幫助你提升效率,比如,,,,是的,如你所見,以開頭的指令是它的獨特標(biāo)識行左右的代碼量,讓應(yīng)用的開發(fā)和加載的一瞬完成倉庫指令往下看之前,請大家沐浴更衣,因為我要講的指令了中的已經(jīng)被占用 showImg(https://segmentfault.com/img/remote/1460000012478667?w=1920&h=926...
摘要:是一個輕巧的框架它實現(xiàn)了數(shù)據(jù)的雙向綁定并提供一些基本的指令幫助你提升效率,比如,,,,是的,如你所見,以開頭的指令是它的獨特標(biāo)識行左右的代碼量,讓應(yīng)用的開發(fā)和加載的一瞬完成倉庫啟動首先我們來看一下是如何啟動的是的掛載點,它決定在多大范圍的樹 showImg(https://segmentfault.com/img/remote/1460000012478667?w=1920&h=926...
摘要:是一個輕巧的框架它實現(xiàn)了數(shù)據(jù)的雙向綁定并提供一些基本的指令幫助你提升效率,比如,,,,是的,如你所見,以開頭的指令是它的獨特標(biāo)識行左右的代碼量,讓應(yīng)用的開發(fā)和加載的一瞬完成倉庫訂閱清單前文說到提供了一個強大的接口我們就用它來劫持?jǐn)?shù)據(jù)不過在此 showImg(https://segmentfault.com/img/remote/1460000012478667?w=1920&h=926...
摘要:支持通過搭建親測地址。演示鏈接演示地址安裝使用由于本項目基于開發(fā),新手建議查看的環(huán)境要求再進行部署。捐贈提供技術(shù)安裝服務(wù)。 OLAINDEX ? Another OneDrive Directory Index. showImg(https://segmentfault.com/img/remote/1460000016747233?w=800&h=400); 此圖來自 如有樂享,感謝...
摘要:自動化打包上文章概述本文分為上下兩篇,上篇主要介紹一些常用的插件也是此次打包主要用的插件,而下篇主要以一個項目為例,從本地出合適的版本,壓縮合并到最后打成包,發(fā)送至指定目錄,做一個全面的演示。 gulp自動化打包(上) 文章概述 本文分為上下兩篇,上篇主要介紹一些常用的gulp插件(也是此次打包主要用的gulp插件),而下篇主要以一個demo項目為例,從本地checkout出合適的g...
閱讀 965·2019-08-30 15:55
閱讀 557·2019-08-26 13:56
閱讀 2090·2019-08-26 12:23
閱讀 3311·2019-08-26 10:29
閱讀 610·2019-08-26 10:17
閱讀 2878·2019-08-23 16:53
閱讀 708·2019-08-23 15:55
閱讀 2833·2019-08-23 14:25