vue?parseHTML?函數(shù)拿到返回值后的處理源碼解析
引言
繼上篇文章:
var startTagMatch = parseStartTag(); if (startTagMatch) { handleStartTag(startTagMatch); if (shouldIgnoreFirstNewline(startTagMatch.tagName, html)) { advance(1); } continue }
在上個(gè)章節(jié)中知道startTagMatch 就是獲取parseStartTag函數(shù)的返回值。并只有在成功匹配到開始標(biāo)簽的情況下parseStartTag 才會(huì)返回解析結(jié)果(一個(gè)對(duì)象),否則返回undefined。
假設(shè)有如下html(template)字符串:
<div id="box" v-if="watings"></div>
parseStartTag函數(shù)返回值
則parseStartTag函數(shù)的返回值如下:
match = { tagName: 'div', attrs: [ [ 'id="box"', 'id', '=', 'box', undefined, undefined ], [ ' v-if="watings"', 'v-if', '=', 'watings', undefined, undefined ] ], start: index, unarySlash: undefined, end: index }
handleStartTag源碼
現(xiàn)在我們假設(shè)匹配成功,那么if語(yǔ)句塊中的代碼將會(huì)被執(zhí)行,此時(shí)會(huì)將解析結(jié)果作為參數(shù)傳遞給 handleStartTag 函數(shù),handleStartTag源碼如下:
function handleStartTag(match) { var tagName = match.tagName; var unarySlash = match.unarySlash; if (expectHTML) { if (lastTag === 'p' && isNonPhrasingTag(tagName)) { parseEndTag(lastTag); } if (canBeLeftOpenTag$$1(tagName) && lastTag === tagName) { parseEndTag(tagName); } } var unary = isUnaryTag$$1(tagName) || !!unarySlash; var l = match.attrs.length; var attrs = new Array(l); for (var i = 0; i < l; i++) { var args = match.attrs[i]; var value = args[3] || args[4] || args[5] || ''; var shouldDecodeNewlines = tagName === 'a' && args[1] === 'href' ? options.shouldDecodeNewlinesForHref : options.shouldDecodeNewlines; attrs[i] = { name: args[1], value: decodeAttr(value, shouldDecodeNewlines) }; } if (!unary) { stack.push({ tag: tagName, lowerCasedTag: tagName.toLowerCase(), attrs: attrs }); lastTag = tagName; } if (options.start) { options.start(tagName, attrs, unary, match.start, match.end); } }
tagName 及unarySlash
handleStartTag函數(shù)用來(lái)處理開始標(biāo)簽的解析結(jié)果,所以它接收parseStartTag函數(shù)的返回值作為參數(shù)。handleStartTag函數(shù)的一開始定義兩個(gè)常量:tagName 以及 unarySlash:
var tagName = match.tagName; var unarySlash = match.unarySlash;
根據(jù)上章節(jié)的內(nèi)容就能理解,tagName 存儲(chǔ)解析開始標(biāo)簽的標(biāo)簽名,unarySlash 可以根據(jù)他的值判斷是解析的開始標(biāo)簽是否為一元標(biāo)簽。
接著是一個(gè)if語(yǔ)句塊,if語(yǔ)句的判斷條件是if (expectHTML),前面說過expectHTML 是parser選項(xiàng),是一個(gè)布爾值,如果為真則該 if 語(yǔ)句塊的代碼將被執(zhí)行。但是現(xiàn)在我們暫時(shí)不看這段代碼,因?yàn)檫@段代碼包含 parseEndTag 函數(shù)的調(diào)用,所以待我們講解完 parseEndTag 函數(shù)之后,再回頭來(lái)說這段代碼。
在往下定義了三個(gè)變量:
var unary = isUnaryTag$$1(tagName) || !!unarySlash; var l = match.attrs.length; var attrs = new Array(l);
變量 unary 是一個(gè)布爾值,當(dāng)它為真時(shí)代表著標(biāo)簽是一元標(biāo)簽,否則是二元標(biāo)簽。
他們通過isUnaryTag來(lái)判斷,其原理通過傳遞的標(biāo)簽名判斷是否有跟預(yù)設(shè)標(biāo)準(zhǔn)HTML中規(guī)定的那些一元標(biāo)簽一致。
l 和 attrs ,其中常量 l 的值存儲(chǔ)著 match.attrs 數(shù)組的長(zhǎng)度,而 attrs 常量則是一個(gè)與match.attrs數(shù)組長(zhǎng)度相等的數(shù)組。
這兩個(gè)常量將被用于接下來(lái)的for循環(huán)中:
for (var i = 0; i < l; i++) { var args = match.attrs[i]; var value = args[3] || args[4] || args[5] || ''; var shouldDecodeNewlines = tagName === 'a' && args[1] === 'href' ? options.shouldDecodeNewlinesForHref : options.shouldDecodeNewlines; attrs[i] = { name: args[1], value: decodeAttr(value, shouldDecodeNewlines) }; }
具體看一下循環(huán)體的代碼,首先定義 args 常量,它的值就是每個(gè)屬性的解析結(jié)果,即match.attrs 數(shù)組中的元素對(duì)象。
變量 value 中就保存著最終的屬性值,如果第4、5、6 項(xiàng)都沒有獲取到屬性值,那么屬性值將被設(shè)置為一個(gè)空字符串:''。
屬性值獲取到了之后,就可以拼裝最終的 attrs 數(shù)組。
attrs 數(shù)組的每個(gè)元素對(duì)象只包含兩個(gè)元素,即屬性名 name 和屬性值 value ,對(duì)于屬性名直接從 args[1] 中即可獲取,但我們發(fā)現(xiàn)屬性值卻沒有直接使用前面獲取到的 value ,而是將傳value 遞給了decodeAttr 函數(shù),并使用該函數(shù)的返回值作為最終的屬性值。
decodeAttr 函數(shù)的作用是對(duì)屬性值中所包含的 html 實(shí)體進(jìn)行解碼,將其轉(zhuǎn)換為實(shí)體對(duì)應(yīng)的字符。關(guān)于 shouldDecodeNewlinesForHref 與 shouldDecodeNewlines 可回顧章節(jié)
Vue編譯器源碼分析compileToFunctions作用
接下來(lái)是:
if (!unary) { stack.push({ tag: tagName, lowerCasedTag: tagName.toLowerCase(), attrs: attrs }); lastTag = tagName; }
這個(gè)if條件是當(dāng)開始標(biāo)簽是非一元標(biāo)簽時(shí)才會(huì)執(zhí)行,其目的是: 如果開始標(biāo)簽是非一元標(biāo)簽,則將該開始標(biāo)簽的信息入棧,即push到stack數(shù)組中,并將lastTag的值設(shè)置為該標(biāo)簽名。
在講解 parseHTML 函數(shù)開頭定義的變量和常量的過程中,我們講解過 stack 常量以及l(fā)astTage 變量,其目的是將來(lái)判斷是否缺少閉合標(biāo)簽,并且現(xiàn)在大家應(yīng)該知道為什么 lastTag 所存儲(chǔ)的標(biāo)簽名字始終保存著 stack 棧頂?shù)脑亓恕?/p>
調(diào)用parser鉤子函數(shù)
最后一段代碼調(diào)用parser鉤子函數(shù)的:
if (options.start) { options.start(tagName, attrs, unary, match.start, match.end); }
如果 parser 選項(xiàng)中包含 options.start 函數(shù),則調(diào)用之,并將開始標(biāo)簽的名字 tagName ,格式化后的屬性數(shù)組 attrs ,是否為一元標(biāo)簽 unary ,以及開始標(biāo)簽在原 html 中的開始和結(jié)束位置match.start 和 match.end 作為參數(shù)傳遞。
接下來(lái)我們分析 parse 到結(jié)束標(biāo)簽之后會(huì)怎么做。
parseHTML 函數(shù)源碼解析之解析器遇到結(jié)束標(biāo)簽
以上就是vue parseHTML 函數(shù)源碼解析的詳細(xì)內(nèi)容,更多關(guān)于vue parseHTML 函數(shù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
unplugin-svg-component優(yōu)雅使用svg圖標(biāo)指南
這篇文章主要為大家介紹了unplugin-svg-component優(yōu)雅使用svg圖標(biāo)指南,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03vue按住shift鍵多選方式(以element框架的table為例)
這篇文章主要介紹了vue按住shift鍵多選方式(以element框架的table為例),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03vue+elementUI動(dòng)態(tài)生成面包屑導(dǎo)航教程
今天小編就為大家分享一篇vue+elementUI動(dòng)態(tài)生成面包屑導(dǎo)航教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2019-11-11vant開發(fā)微信小程序安裝以及簡(jiǎn)單使用教程
這篇文章主要介紹了vant開發(fā)微信小程序安裝以及簡(jiǎn)單使用教程,需要的朋友可以參考下2022-12-12vue實(shí)現(xiàn)書本翻頁(yè)動(dòng)畫效果實(shí)例詳解
這篇文章主要介紹了vue簡(jiǎn)單實(shí)現(xiàn)書本翻頁(yè)效果,需要的朋友可以參考下2022-04-04