承繼上篇內(nèi)容:下面是parseHTML 函數(shù)源碼解析
var startTagMatch = parseStartTag(); if (startTagMatch) { handleStartTag(startTagMatch); if (shouldIgnoreFirstNewline(startTagMatch.tagName, html)) { advance(1); } continue }
在之前這篇文章中寫明startTagMatch 就用來獲取parseStartTag函數(shù)的返回值。并只有在成功匹配到開始標簽的情況下parseStartTag 才會返回解析結(jié)果(一個對象),否則返回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源碼
如果匹配成功,if語句代碼被執(zhí)行,得出的結(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ù)的作用就是處理標簽的解析結(jié)果,所以它接收parseStartTag函數(shù)的返回值作為參數(shù)。handleStartTag函數(shù)的一開始定義兩個常量:tagName 以及 unarySlash:
var tagName = match.tagName; var unarySlash = match.unarySlash;
通過對于上章節(jié)內(nèi)容解析,tagName 存儲解析開始標簽的標簽名,unarySlash 是判斷開始標簽是否為一元標簽。
接著是一個if語句塊,if語句的判斷條件是if (expectHTML),前面說過expectHTML 是parser選項,是一個布爾值,如果為真則該 if 語句塊的代碼將被執(zhí)行。但是現(xiàn)在我們暫時不看這段代碼,因為這段代碼包含 parseEndTag 函數(shù)的調(diào)用,所以待我們講解完 parseEndTag 函數(shù)之后,再回頭來說這段代碼。
在往下定義了三個變量:
var unary = isUnaryTag$$1(tagName) || !!unarySlash; var l = match.attrs.length; var attrs = new Array(l);
變量 unary 是一個布爾值,當它為真時代表著標簽是一元標簽,否則是二元標簽。
他們通過isUnaryTag來判斷,其原理通過傳遞的標簽名判斷是否有跟預(yù)設(shè)標準HTML中規(guī)定的那些一元標簽一致。
l 和 attrs ,其中常量 l 的值存儲著 match.attrs 數(shù)組的長度,而 attrs 常量則是一個與match.attrs數(shù)組長度相等的數(shù)組。
這兩個常量將被用于接下來的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 常量,它的值就是每個屬性的解析結(jié)果,即match.attrs 數(shù)組中的元素對象。
變量 value 中就保存著最終的屬性值,如果第4、5、6 項都沒有獲取到屬性值,那么屬性值將被設(shè)置為一個空字符串:''。
屬性值獲取到了之后,就可以拼裝最終的 attrs 數(shù)組。
attrs 數(shù)組的每個元素對象只包含兩個元素,即屬性名 name 和屬性值 value ,對于屬性名直接從 args[1] 中即可獲取,但我們發(fā)現(xiàn)屬性值卻沒有直接使用前面獲取到的 value ,而是將傳value 遞給了decodeAttr 函數(shù),并使用該函數(shù)的返回值作為最終的屬性值。
decodeAttr 函數(shù)的作用是對屬性值中所包含的 html 實體進行解碼,將其轉(zhuǎn)換為實體對應(yīng)的字符。關(guān)于 shouldDecodeNewlinesForHref 與 shouldDecodeNewlines 可回顧章節(jié)
接下來是:
if (!unary) { stack.push({ tag: tagName, lowerCasedTag: tagName.toLowerCase(), attrs: attrs }); lastTag = tagName; }
這個if條件是當開始標簽是非一元標簽時才會執(zhí)行,其目的是: 如果開始標簽是非一元標簽,則將該開始標簽的信息入棧,即push到stack數(shù)組中,并將lastTag的值設(shè)置為該標簽名。
在講解 parseHTML 函數(shù)開頭定義的變量和常量的過程中,我們講解過 stack 常量以及l(fā)astTage 變量,其目的是將來判斷是否缺少閉合標簽,并且現(xiàn)在大家應(yīng)該知道為什么 lastTag 所存儲的標簽名字始終保存著 stack 棧頂?shù)脑亓恕?/p>
調(diào)用parser鉤子函數(shù)
最后一段代碼調(diào)用parser鉤子函數(shù)的:
if (options.start) { options.start(tagName, attrs, unary, match.start, match.end); }
當 parser 選項中包含 options.start 函數(shù),表示調(diào)用,同時將開始標簽的名字命名為tagName ,當格式化后的屬性數(shù)組為 attrs。那是不是一元標簽 unary ,且開始標簽的開始和技術(shù)位置是在原 html 中match.start 和 match.end 作為參數(shù)傳遞。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/127766.html
摘要:寫文章不容易,點個贊唄兄弟專注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學習吧研究基于版本如果你覺得排版難看,請點擊下面鏈接或者拉到下面關(guān)注公眾號也可以吧原理源碼版嗨,又到周末啦,又可以睡 寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學習吧研究基于...
摘要:寫文章不容易,點個贊唄兄弟專注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學習吧研究基于版本如果你覺得排版難看,請點擊下面鏈接或者拉到下面關(guān)注公眾號也可以吧原理白話版插槽作為組件一個重要的部 寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學習吧研究基于...
摘要:我們會在后面的源碼倉庫全解析第三章下存儲提供方礦工的配置操作章節(jié)重點介紹這個過程。參考文獻本章贊助品牌深圳牛鏈科技有限公司,是一家專注存儲類礦機研發(fā)生產(chǎn)銷售托管為一體的高科技企業(yè)。感謝深圳牛鏈科技有限公司對嘉樂的原創(chuàng)內(nèi)容提供支持。 歡迎大家來到第三章,經(jīng)過 前章《【Filecoin源碼倉庫全解析】第二章:如何創(chuàng)建賬戶錢包并獲取FIL Mock代幣的內(nèi)容閱讀后,我們應(yīng)該能順利在Filec...
摘要:最近在看源碼,發(fā)覺以前對的理解實在浮淺,這里記錄了一些以前疏忽的點。和在里面,經(jīng)過的解析后,會變成執(zhí)行后的結(jié)果。原來對的理解就是類似這種寫法,現(xiàn)在看了實現(xiàn)之后才理解。 最近在看react源碼,發(fā)覺以前對react的理解實在浮淺,這里記錄了一些以前疏忽的點。 createElement和component 在react里面,經(jīng)過babel的解析后,jsx會變成createElement執(zhí)...
摘要:所以我們分析這個新需求的效果我們在函數(shù)執(zhí)行到一半時,執(zhí)行了,的返回值為后續(xù)函數(shù)的執(zhí)行返回值。也就是說,我們在中處理,直接調(diào)用隊列中的下一個函數(shù)即可然后監(jiān)聽和回調(diào),即可在當前函數(shù)中獲取到返回值拿到返回值后就可以執(zhí)行我們后續(xù)的代碼。 最近想到了一個自認為很有意思的面試題如何實現(xiàn)一個compose函數(shù)。函數(shù)接收數(shù)個參數(shù),參數(shù)均為Function類型,右側(cè)函數(shù)的執(zhí)行結(jié)果將作為左側(cè)函數(shù)執(zhí)行的參數(shù)...
閱讀 687·2023-03-27 18:33
閱讀 889·2023-03-26 17:27
閱讀 756·2023-03-26 17:14
閱讀 738·2023-03-17 21:13
閱讀 668·2023-03-17 08:28
閱讀 2092·2023-02-27 22:32
閱讀 1521·2023-02-27 22:27
閱讀 2432·2023-01-20 08:28