Vue模板解析
Html文件example
<div id="app">
<div v-if="show">v-if</div>
<div v-text="msg"></div>
</div>
处理过程
- 循环遍历HTML
- 遇到标签tag的起始,调用start方法,设置根节点
root=element、currentElement=element将currentElement压入stack
- 遇到
<div v-if="show">的时候,当前有currentElement了,currentElement.children = element,然后currentElement = element,将currentElement压入stack
- 遇到文字“v-if”,调用chars方法将对象化的文字
{type: 3, text: "v-if"}挂载到currentElement.children上
- 遇到
</div>的结束tag,调用end方法,将currentElement从stack中pop出来,这里还有一步优化操作就是在pop之前判断一下是不是' '如果是的话会吧currentElement.childrenpop出去
- 重复2、3、4、5
- 调用generate方法生成render方法。
- 初始化Watcher
- 调用this.get,触getter
- _update -> _render(内部调用生成的render生成VNode)
- 调用渲染 具体是__patch__
- 逐级生成DOM
处理结果
- ast解析结果如下图:

- v-if&文字节点结果如下图:

- v-text结果如下图:

- render方法返回
code.render = "with(this){return _c('div',{attrs:{"id":"app"}},[(show)?_c('div',[_v("v-if")]):_e(),_v(" "),_c('div',{domProps:{"textContent":_s(msg)}})])}"
这个_c函数就是在initRender中赋值的createElement方法
代码解析
parseHtml源码
while (html) {
last = html
// Make sure we're not in a plaintext content element like script/style
if (!lastTag || !isPlainTextElement(lastTag)) {
let textEnd = html.indexOf('<')
if (textEnd === 0) {
// End tag:</div>这种
const endTagMatch = html.match(endTag)
if (endTagMatch) { //如果是end tag就吧html中这个标签删掉得到新的html
const curIndex = index
advance(endTagMatch[0].length)
parseEndTag(endTagMatch[1], curIndex, index) // 这里会把stack中的对应标签的element pop出来
continue
}
// Start tag: 比如<div id="app">
const startTagMatch = parseStartTag()
if (startTagMatch) {
// 处理第一行的tag 会将当前tag的element push到stack中
handleStartTag(startTagMatch)
if (shouldIgnoreFirstNewline(lastTag, html)) {
advance(1)
}
continue
}
}
let text, rest, next
if (textEnd >= 0) { //处理文字内容的
rest = html.slice(textEnd)
while ( //处理空的tag
!endTag.test(rest) &&
!startTagOpen.test(rest) &&
!comment.test(rest) &&
!conditionalComment.test(rest)
) {
// < in plain text, be forgiving and treat it as text
next = rest.indexOf('<', 1)
if (next < 0) break
textEnd += next
rest = html.slice(textEnd)
}
text = html.substring(0, textEnd) // 获得真是的text 比如<div>test</div>中的test
advance(textEnd)
}
if (textEnd < 0) {
text = html
html = ''
}
if (options.chars && text) {
// 处理文字的函数,这里会将text内容生成对象 {type:3,text: 'test' } 赋值给element.children
options.chars(text)
}
} else {
// 处理<script>等标签
}
// 处理最后可能存在的文字
if (html === last) {
options.chars && options.chars(html)
if (process.env.NODE_ENV !== 'production' && !stack.length && options.warn) {
options.warn(`Mal-formatted tag at end of template: "${html}"`)
}
break
}
parseStartTag
// 正则表达将start tag中的各种属性匹配出来
function parseStartTag () {
const start = html.match(startTagOpen)
if (start) {
const match = {
tagName: start[1],
attrs: [],
start: index
}
advance(start[0].length)
let end, attr
// 判断条件 不是'>'并且能够匹配出xx=xx 的形式
while (!(end = html.match(startTagClose)) && (attr = html.match(attribute))) {
advance(attr[0].length)
match.attrs.push(attr)
}
if (end) {
match.unarySlash = end[1]
advance(end[0].length)
match.end = index
return match
}
}
}
function handleStartTag (match) {
const tagName = match.tagName
const unarySlash = match.unarySlash
const l = match.attrs.length
const attrs = new Array(l)
// attrs是一个二维数组
for (let i = 0; i < l; i++) {
const args = match.attrs[i] // 匹配结果是match操作的结果
const value = args[3] || args[4] || args[5] || ''
attrs[i] = {
name: args[1],
value: decodeAttr(
value,
options.shouldDecodeNewlines
)
}
}
if (!unary) {
stack.push({ tag: tagName, lowerCasedTag: tagName.toLowerCase(), attrs: attrs })
lastTag = tagName
}
if (options.start) {
// 调用start方法,start方法主要是生成ast数据结构
options.start(tagName, attrs, unary, match.start, match.end)
}
}
流程图

参考文章
Vue2.0 源码阅读:模板渲染
Vue源码分析(7)--实例分析v-if
TO DO
接下来就是调用mount方法,然后进行new Watcher等数据依赖收集。
Vue模板解析
Html文件example
处理过程
root=element、currentElement=element将currentElement压入stack<div v-if="show">的时候,当前有currentElement了,currentElement.children = element,然后currentElement = element,将currentElement压入stack{type: 3, text: "v-if"}挂载到currentElement.children上</div>的结束tag,调用end方法,将currentElement从stack中pop出来,这里还有一步优化操作就是在pop之前判断一下是不是' '如果是的话会吧currentElement.childrenpop出去处理结果
这个_c函数就是在initRender中赋值的createElement方法
代码解析
parseHtml源码
parseStartTag
流程图
参考文章
Vue2.0 源码阅读:模板渲染
Vue源码分析(7)--实例分析v-if
TO DO
接下来就是调用mount方法,然后进行new Watcher等数据依赖收集。