parseHTML()執行完第一次循環以後,html變成:javascript
接下來開始執行第二次循環,解析的是文本"(回車)請輸入:"html
while (html) { last = html; if (!lastTag || !isPlainTextElement(lastTag)) { var textEnd = html.indexOf('<'); if (textEnd === 0) { /*當新的html以<開頭,執行如下代碼*/ } //新的循環執行這段 var text = (void 0), rest = (void 0), next = (void 0); if (textEnd >= 0) { //截取字符串,存放在rest中 rest = html.slice(textEnd); while ( !endTag.test(rest) && !startTagOpen.test(rest) && !comment.test(rest) && !conditionalComment.test(rest) ) { // 若是純文本中存在<,做爲文本處理 next = rest.indexOf('<', 1); if (next < 0) { break } textEnd += next; rest = html.slice(textEnd); } //獲取文本字符串,此處就是‘(回車)請輸入:’ text = html.substring(0, textEnd); //從新修改index索引,從新截取html advance(textEnd); } if (textEnd < 0) { text = html; html = ''; } if (options.chars && text) { //調用parseHTML裏面定義的chars方法 options.chars(text); } } else { /*代碼已省略*/ } //當html是最後一段時間運行這段代碼 if (html === last) { /*代碼已省略*/ } }
第二次循環,字符串爲純文本"(回車)請輸入:",因此會繼續執行下面的代碼,調用parseHTML裏面定義的chars方法。java
chars: function chars (text) { if (!currentParent) { { if (text === template) { warnOnce( 'Component template requires a root element, rather than just text.' ); } else if ((text = text.trim())) { warnOnce( ("text \"" + text + "\" outside root element will be ignored.") ); } } return } // 處理IE下textarea placeholder的 bug,學習於https://blog.csdn.net/wide288/article/details/51094041 if (isIE && currentParent.tag === 'textarea' && currentParent.attrsMap.placeholder === text ) { return } var children = currentParent.children; text = inPre || text.trim() ? isTextTag(currentParent) ? text : decodeHTMLCached(text) // only preserve whitespace if its not right after a starting tag : preserveWhitespace && children.length ? ' ' : ''; if (text) { var res; if (!inVPre && text !== ' ' && (res = parseText(text, delimiters))) { children.push({ type: 2, expression: res.expression, tokens: res.tokens, text: text }); } else if (text !== ' ' || !children.length || children[children.length - 1].text !== ' ') { //將解析後的text push到children數組 children.push({ type: 3, text: text }); } } }
chars方法對text進行處理,並轉換成children添加到當天父節點下。這裏text是純靜態文本,走的代碼是children.push({type: 3,text: text});
,將type定爲3,若text是{{message}},則走的是children.push({type: 2,expression: res.expression, tokens: res.tokens,text: text});
,將type設爲2。
接下來執行第三次循環,解析<input type="text" v-model="message">
express
解析過程與第一次相同。
第四次循環解析<br/>
數組
解析過程與第一次相同。
第五次循環解析的時<的位置是1,所以解析的實際上是回車,,text就是"",解析過程與第二次相同。但最後在調用end方法是,該條children會從數組中pop出來。ide
第六次循環解析的就是結束標籤</div>
學習
在parseHTML()匹配到endTag以後調用parseEndTag()方法。ui
function parseEndTag (tagName, start, end) { var pos, lowerCasedTagName; if (start == null) { start = index; } if (end == null) { end = index; } //標籤名轉成小寫 if (tagName) { lowerCasedTagName = tagName.toLowerCase(); } // 獲取與結束標籤匹配的最近的標籤 if (tagName) { for (pos = stack.length - 1; pos >= 0; pos--) { if (stack[pos].lowerCasedTag === lowerCasedTagName) { break } } } else { // If no tag name is provided, clean shop pos = 0; } if (pos >= 0) { // Close all the open elements, up the stack for (var i = stack.length - 1; i >= pos; i--) { //// 提示沒有匹配的標籤 if ("development" !== 'production' && (i > pos || !tagName) && options.warn ) { options.warn( ("tag <" + (stack[i].tag) + "> has no matching end tag.") ); } if (options.end) { options.end(stack[i].tag, start, end); } } //對應將stack數組進行變更 //pos=0; stack.length = pos; lastTag = 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); } } }
parseEndTag()首先對閉合標籤進行匹配,將start和end的值設爲index最後的索引值,即html的末位,而後調用options裏面的end方法清空stack,最後修改stack的長度爲0。end方法的代碼以下:spa
end: function end () { // 獲取對象與文本 var element = stack[stack.length - 1]; var lastNode = element.children[element.children.length - 1]; if (lastNode && lastNode.type === 3 && lastNode.text === ' ' && !inPre) { //若是lastNode是空文本,把lastNode彈出 element.children.pop(); } // pop stack stack.length -= 1; currentParent = stack[stack.length - 1]; closeElement(element); }
至此parseHTML循環結束,返回的ast對象有以下這些信息:.net