首頁 > 軟體

vue parseHTML 函數拿到返回值後的處理原始碼解析

2022-07-13 22:02:08

引言

繼上篇文章:

parseHTML 函數原始碼解析

var startTagMatch = parseStartTag();
if (startTagMatch) {
	handleStartTag(startTagMatch);
	if (shouldIgnoreFirstNewline(startTagMatch.tagName, html)) {
		advance(1);
	}
	continue
}

在上個章節中知道startTagMatch 就是獲取parseStartTag函數的返回值。並只有在成功匹配到開始標籤的情況下parseStartTag 才會返回解析結果(一個物件),否則返回undefined。

假設有如下html(template)字串:

<div id="box" v-if="watings"></div>

parseStartTag函數返回值

則parseStartTag函數的返回值如下:

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語句塊中的程式碼將會被執行,此時會將解析結果作為引數傳遞給 handleStartTag 函數,handleStartTag原始碼如下:

function handleStartTag(match) {
	var tagName = match.tagName;
	var unarySlash = match.unarySlash;
	if (expectHTML) {
		if (lastTag === 'p' &amp;&amp; isNonPhrasingTag(tagName)) {
			parseEndTag(lastTag);
		}
		if (canBeLeftOpenTag$$1(tagName) &amp;&amp; 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 &lt; l; i++) {
		var args = match.attrs[i];
		var value = args[3] || args[4] || args[5] || '';
		var shouldDecodeNewlines = tagName === 'a' &amp;&amp; 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函數用來處理開始標籤的解析結果,所以它接收parseStartTag函數的返回值作為引數。handleStartTag函數的一開始定義兩個常數:tagName 以及 unarySlash:

var tagName = match.tagName;
var unarySlash = match.unarySlash;

根據上章節的內容就能理解,tagName 儲存解析開始標籤的標籤名,unarySlash 可以根據他的值判斷是解析的開始標籤是否為一元標籤。

接著是一個if語句塊,if語句的判斷條件是if (expectHTML),前面說過expectHTML 是parser選項,是一個布林值,如果為真則該 if 語句塊的程式碼將被執行。但是現在我們暫時不看這段程式碼,因為這段程式碼包含 parseEndTag 函數的呼叫,所以待我們講解完 parseEndTag 函數之後,再回頭來說這段程式碼。

在往下定義了三個變數:

var unary = isUnaryTag$$1(tagName) || !!unarySlash;
var l = match.attrs.length;
var attrs = new Array(l);

變數 unary 是一個布林值,當它為真時代表著標籤是一元標籤,否則是二元標籤。

他們通過isUnaryTag來判斷,其原理通過傳遞的標籤名判斷是否有跟預設標準HTML中規定的那些一元標籤一致。

l 和 attrs ,其中常數 l 的值儲存著 match.attrs 陣列的長度,而 attrs 常數則是一個與match.attrs陣列長度相等的陣列。

這兩個常數將被用於接下來的for迴圈中:

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)
	};
}

具體看一下回圈體的程式碼,首先定義 args 常數,它的值就是每個屬性的解析結果,即match.attrs 陣列中的元素物件。

變數 value 中就儲存著最終的屬性值,如果第4、5、6 項都沒有獲取到屬性值,那麼屬性值將被設定為一個空字串:''。

屬性值獲取到了之後,就可以拼裝最終的 attrs 陣列。

attrs 陣列的每個元素物件只包含兩個元素,即屬性名 name 和屬性值 value ,對於屬性名直接從 args[1] 中即可獲取,但我們發現屬性值卻沒有直接使用前面獲取到的 value ,而是將傳value 遞給了decodeAttr 函數,並使用該函數的返回值作為最終的屬性值。

decodeAttr 函數的作用是對屬性值中所包含的 html 實體進行解碼,將其轉換為實體對應的字元。關於 shouldDecodeNewlinesForHref 與 shouldDecodeNewlines 可回顧章節

Vue編譯器原始碼分析compileToFunctions作用

接下來是:

if (!unary) {
	stack.push({
		tag: tagName,
		lowerCasedTag: tagName.toLowerCase(),
		attrs: attrs
	});
	lastTag = tagName;
}

這個if條件是當開始標籤是非一元標籤時才會執行,其目的是: 如果開始標籤是非一元標籤,則將該開始標籤的資訊入棧,即push到stack陣列中,並將lastTag的值設定為該標籤名。

在講解 parseHTML 函數開頭定義的變數和常數的過程中,我們講解過 stack 常數以及lastTage 變數,其目的是將來判斷是否缺少閉合標籤,並且現在大家應該知道為什麼 lastTag 所儲存的標籤名字始終儲存著 stack 棧頂的元素了。

呼叫parser勾點函數

最後一段程式碼呼叫parser勾點函數的:

if (options.start) {
	options.start(tagName, attrs, unary, match.start, match.end);
}

如果 parser 選項中包含 options.start 函數,則呼叫之,並將開始標籤的名字 tagName ,格式化後的屬性陣列 attrs ,是否為一元標籤 unary ,以及開始標籤在原 html 中的開始和結束位置match.start 和 match.end 作為引數傳遞。

接下來我們分析 parse 到結束標籤之後會怎麼做。

parseHTML 函數原始碼解析

以上就是vue parseHTML 函數原始碼解析的詳細內容,更多關於vue parseHTML 函數的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com