我们用一个简单的例子来说明一下:
<div id="demo"> <h1>Latest Vue.js Commits</h1> <p>{{1 + 1}}</p> </div>
我们想一想这段代码会生成什么样的 AST 呢?
我们这个例子最后生成的大概就是这么一棵树,那么 Vue 是如何去做这样一些解析的呢?我们继续看。
在 parse 函数中,我们先是定义了非常多的全局属性以及函数,然后调用了 parseHTML 这么一个函数,这也是 parse 最核心的函数,这个函数会不断的解析模板,填充 root,最后把 root(AST) 返回回去。
parseHTML
在这个函数中,最重要的是 while 循环中的代码,而在解析过程中发挥重要作用的有这么几个正则表达式。
const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/ const ncname = '[a-zA-Z_][\\w\\-\\.]*' const qnameCapture = `((?:${ncname}\\:)?${ncname})` const startTagOpen = new RegExp(`^<${qnameCapture}`) const startTagClose = /^\s*(\/?)>/ const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`) const doctype = /^<!DOCTYPE [^>]+>/i const comment = /^<!\--/ const conditionalComment = /^<!\[/
Vue 通过上面几个正则表达式去匹配开始结束标签、标签名、属性等等。
关于 while 的详细注解我放在我仓库里了,有兴趣的可以去看看。
在 while 里,其实就是不断的去用 html.indexOf('<')
去匹配,然后根据返回的索引的不同去做不同的解析处理:
- __等于 0:__这就代表这是注释、条件注释、doctype、开始标签、结束标签中的某一种
- __大于等于 0:__这就说明是文本、表达式
- __小于 0:__表示 html 标签解析完了,可能会剩下一些文本、表达式
parse 函数就是不断的重复这个工作,然后将 template 转换成 AST,在解析过程中,其实对于标签与标签之间的空格,Vue 也做了优化处理,有些元素之间的空格是没用的。
compile 其实要说要说非常多的篇幅,但是这里只能简单的理一下思路,具体代码还需要各位下去深扣。
优化器
从代码中的注释我们可以看出,优化器的目的就是去找出 AST 中纯静态的子树:
把纯静态子树提升为常量,每次重新渲染的时候就不需要创建新的节点了
在 patch 的时候就可以跳过它们
optimize 的代码量没有 parse 那么多,我们来看看:
export function optimize (root: ?ASTElement, options: CompilerOptions) { // 判断 root 是否存在 if (!root) return // 判断是否是静态的属性 // 'type,tag,attrsList,attrsMap,plain,parent,children,attrs' isStaticKey = genStaticKeysCached(options.staticKeys || '') // 判断是否是平台保留的标签,html 或者 svg 的 isPlatformReservedTag = options.isReservedTag || no // 第一遍遍历: 给所有静态节点打上是否是静态节点的标记 markStatic(root) // 第二遍遍历:标记所有静态根节点 markStaticRoots(root, false) }
内容版权声明:除非注明,否则皆为本站原创文章。