parseHTML()执行完第一次循环之后,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方法。
chars
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">
解析过程与第一次相同。
第四次循环解析<br/>
解析过程与第一次相同。
第五次循环解析的时<的位置是1,因此解析的其实是回车,,text就是"",解析过程与第二次相同。但最后在调用end方法是,该条children会从数组中pop出来。
第六次循环解析的就是结束标签</div>
在parseHTML()匹配到endTag之后调用parseEndTag()方法。
parseEndTag
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方法的代码如下:
end
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对象有如下这些信息:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。