.8-Vue源码之AST(4)
上一節(jié)講完了超長(zhǎng)的start函數(shù),也同時(shí)完結(jié)了handleStartTag函數(shù),接著continue進(jìn)入下一輪while循環(huán)。
此時(shí)剩余的字符串狀態(tài)如圖:,切掉了<div id='app'>。
再次進(jìn)入while循環(huán)時(shí),發(fā)生了一些變化:
// Line-7672function parseHTML(html, options) {/* code */while (html) {last = html;if (!lastTag || !isPlainTextElement(lastTag)) {var textEnd = html.indexOf('<');// 此時(shí)字符串不是以<開(kāi)頭 所以不會(huì)進(jìn)入此條件if (textEnd === 0) {// ... }var text = (void 0),rest$1 = (void 0),next = (void 0);if (textEnd >= 0) {// 截取<字符索引 => </div>rest$1 = html.slice(textEnd);// 處理文本中的<字符while (!endTag.test(rest$1) &&!startTagOpen.test(rest$1) &&!comment.test(rest$1) &&!conditionalComment.test(rest$1)) {next = rest$1.indexOf('<', 1);if (next < 0) {break}textEnd += next;rest$1 = html.slice(textEnd);}// 獲取中間的字符串 => {{message}}text = html.substring(0, textEnd);advance(textEnd);}// 當(dāng)字符串沒(méi)有<時(shí)if (textEnd < 0) {text = html;html = '';}// 另外一個(gè)函數(shù)if (options.chars && text) {options.chars(text);}} else {/* code */}if (html === last) {/* code */}}// Clean up any remaining tags parseEndTag();// fn...}第一次進(jìn)入while循環(huán)時(shí),由于字符串以<開(kāi)頭,所以進(jìn)入startTag條件,并進(jìn)行AST轉(zhuǎn)換,最后將對(duì)象彈入stack數(shù)組中。
而這一次,字符串開(kāi)頭為{,所以會(huì)繼續(xù)執(zhí)行下面的代碼。代碼將{{message}}作為text抽離出來(lái),并調(diào)用了參數(shù)中另外一個(gè)函數(shù):options.chars。
// Line-8167function chars(text) {if (!currentParent) {// 提示必須有一個(gè)DOM根節(jié)點(diǎn)if (text === template) {warnOnce('Component template requires a root element, rather than just text.');}// 節(jié)點(diǎn)外的文本會(huì)被忽略else if ((text = text.trim())) {warnOnce(("text \"" + text + "\" outside root element will be ignored."));}return}// IE textarea placeholder bugif (isIE &¤tParent.tag === 'textarea' &¤tParent.attrsMap.placeholder === text) {return}var children = currentParent.children;// text => {{message}}text = inPre || text.trim() ?isTextTag(currentParent) ? text : decodeHTMLCached(text) : preserveWhitespace && children.length ? ' ' : '';if (text) {var expression;if (!inVPre && text !== ' ' && (expression = parseText(text, delimiters))) {// 將解析后的text弄進(jìn)children數(shù)組 children.push({type: 2,expression: expression,text: text});} else if (text !== ' ' || !children.length || children[children.length - 1].text !== ' ') {children.push({type: 3,text: text});}}}本函數(shù)的核心為parseText對(duì)text的處理,即{{message}}。
// Line-7928function parseText(text, delimiters) {// 正則選擇var tagRE = delimiters ? buildRegex(delimiters) : defaultTagRE;// 在這里調(diào)用test方法后lasatIndex會(huì)變化if (!tagRE.test(text)) {return}var tokens = [];var lastIndex = tagRE.lastIndex = 0;var match, index;// 匹配到中間的文本while ((match = tagRE.exec(text))) {index = match.index;// 將{{message}}之前的文本push進(jìn)去if (index > lastIndex) {tokens.push(JSON.stringify(text.slice(lastIndex, index)));}// 該方法對(duì)特殊字符進(jìn)行處理 本例暫時(shí)用不上// 返回的仍然是message字符串var exp = parseFilters(match[1].trim());// _s(message)tokens.push(("_s(" + exp + ")"));lastIndex = index + match[0].length;}if (lastIndex < text.length) {// push}}后面的文本 tokens.push(JSON.stringify(text.slice(lastIndex)));}return tokens.join('+')}實(shí)際上text可分為3個(gè)部分,{{之前的,{{}}中間包裹的,}}之后的,函數(shù)分別將三者抽離出來(lái),push進(jìn)了tokens,最后用+連接并返回一個(gè)字符串:
返回后,將此字符串作為值,和其余屬性一個(gè)添加到children數(shù)組中:
處理完后,進(jìn)入下一輪while循環(huán)。
剩余的字符串為</div>,所以進(jìn)入第一個(gè)循環(huán),并且匹配到EndTag的分支。
// Line-7672function parseHTML(html, options) {/* code */while (html) {/* code */var textEnd = html.indexOf('<');if (textEnd === 0) {/* code */var endTagMatch = html.match(endTag);if (endTagMatch) {var curIndex = index;advance(endTagMatch[0].length);parseEndTag(endTagMatch[1], curIndex, index);continue}/* code */}/* code */}/* code */}進(jìn)入endTag分支后,匹配到的endTagMatch如圖所示:
將當(dāng)前索引保存為curIndex,然后根據(jù)匹配到的字符串往前推index,調(diào)用parseEndTag函數(shù)進(jìn)行處理。
// Line-7863function parseEndTag(tagName, start, end) {// 參數(shù)修正var pos, lowerCasedTagName;if (start == null) {start = index;}if (end == null) {end = index;}if (tagName) {lowerCasedTagName = tagName.toLowerCase();}// 獲取最近的匹配標(biāo)簽if (tagName) {for (pos = stack.length - 1; pos >= 0; pos--) {if (stack[pos].lowerCasedTag === lowerCasedTagName) {break}}} else {// If no tag name is provided, clean shoppos = 0;}if (pos >= 0) {for (var i = stack.length - 1; i >= pos; i--) {// 提示沒(méi)有匹配的標(biāo)簽if ("development" !== 'production' &&(i > pos || !tagName) &&options.warn) {options.warn(("tag <" + (stack[i].tag) + "> has no matching end tag."));}// 調(diào)用剩下的一個(gè)參數(shù)函數(shù)if (options.end) {options.end(stack[i].tag, start, end);}}// Remove the open elements from the stackstack.length = pos;// 0lastTag = pos && stack[pos - 1].tag;} else if (lowerCasedTagName === 'br') {if (options.start) {options.start(tagName, [], true, start, end);}} else if (lowerCasedTagName === 'p') {if (options.start) {options.start(tagName, [], false, start, end);}if (options.end) {options.end(tagName, start, end);}}}// Line-8154function end() {// 獲取對(duì)象與文本var element = stack[stack.length - 1];var lastNode = element.children[element.children.length - 1];// type是2 跳過(guò)if (lastNode && lastNode.type === 3 && lastNode.text === ' ' && !inPre) {element.children.pop();}// pop stackstack.length -= 1;// 變成undefined了currentParent = stack[stack.length - 1];endPre(element);}// Line-8010function endPre(element) {if (element.pre) {inVPre = false;}// tag === pre?if (platformIsPreTag(element.tag)) {inPre = false;}}這個(gè)函數(shù)對(duì)閉合標(biāo)簽進(jìn)行配對(duì),并對(duì)應(yīng)將stack數(shù)組進(jìn)行變動(dòng),由于本例只有一個(gè)div,所以stack被清空。
?
完事后,continue進(jìn)入下一輪循環(huán),由于字符串全部被切割完,此時(shí)html為空字符串,此時(shí)while循環(huán)結(jié)束,進(jìn)入下一個(gè)代碼段:
// Line-7672function parseHTML(html, options) {/* code */while (html) {/* code */}// Clean up any remaining tags parseEndTag();/* 一些方法 */}字符串解析完后,再次調(diào)用parseEndTag進(jìn)行收尾工作,函數(shù)內(nèi)部將pos置0,stack置空。
回到了parse函數(shù),并返回了root,即解析后的AST對(duì)象:,包含了標(biāo)簽類(lèi)型、屬性、文本內(nèi)容等。
先結(jié)束了吧。
轉(zhuǎn)載于:https://www.cnblogs.com/QH-Jimmy/p/6957419.html
總結(jié)
以上是生活随笔為你收集整理的.8-Vue源码之AST(4)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: php excel 读取日期问题
- 下一篇: 第十六周工作总结