写点什么

【Vue2.x 源码学习】第十二篇 - 生成 ast 语法树 - 流程说明

用户头像
Brave
关注
发布于: 2021 年 06 月 12 日
【Vue2.x 源码学习】第十二篇 - 生成 ast 语法树-流程说明

一,前言


上篇,主要介绍了 vue 数据渲染核心流程,涉及以下几个点:

初次渲染时

  1. template 模板被编译为 ast 语法树;

  2. 通过 ast 语法树生成 render 函数;

  3. 通过 render 函数返回 vnode 虚拟节点;

  4. 使用 vnode 虚拟节点生成真实 dom 并进行渲染;

视图更新时

  1. 调用 render 函数生成新的 vnode 虚拟节点;

  2. 通过 diff 算法对新老 vnode 虚拟节点进行对比;

  3. 根据虚拟节点比对结果,更新真实 dom;


本篇,生成 ast 语法树-流程说明


二,Vue 提供的使用方式

1,三种模板写法及优先级

<body>  <!-- 第一种 -->  <div id=app>{{message}}</div>  <script src="./vue.js"></script>  <script>    debugger;    let vm = new Vue({      el: '#app',      data() {      },      // 第二种      template:'',      // 第三种      render(){}    });  </script></body>
复制代码


三种写法的优先级【由高到低】:


  • 使用 render

  • 使用 template

  • 使用元素中的内容;即使用 <div id=app>{{message}}</div> 中的 {{message}}

2,两种数据挂载方式

在 Vue2.x 中,提供了两种挂载方式:

let vm = new Vue({  // el: '#app',		// 挂载方式一  data() {  },}).$mount('#app');	// 挂载方式 2
复制代码


当挂载点 vm.$options.el 存在,或直接调用了 Vue 的原型方法 $mount 时,

就会通过 Vue 上的原型方法 $mount 对数据进行挂载操作


三,Vue 的原型方法 $mount


<body>  <div id=app>{{message}}</div>  <script>    let vm = new Vue({      el: '#app',      data() {...},    });   </script></body>
复制代码


当 vm.$options.el 存在,或直接调用 Vue 的原型方法 $mount 时,就会对数据进行挂载操作;

所以,设置 vm.$options.el 或 .$mount,内部都是调用 Vue 原型方法 $mount 进行处理的;


在 $mount 中,拿到 el 挂载点指向的真实 dom 元素,并使用新内容将它替换掉

// src/init.js#initMixin
export function initMixin(Vue) { Vue.prototype._init = function (options) { const vm = this; vm.$options = options; initState(vm);
if (vm.$options.el) { // 将数据挂载到页面上(此时数据已被观测) vm.$mount(vm.$options.el) } }
// 支持 new Vue({el}) 和 new Vue().$mount 两种情况 Vue.prototype.$mount = function (el) { const vm = this; el = document.querySelector(el); // 获取真实的元素 vm.$el = el; // vm.$el 为当前页面上的真实元素 }}
复制代码


如何拿到"id = app"对应的元素,outerHTML or innerHTML?


  • outerHTML:<div id=app>{{message}}</div>

  • innerHTML:{{message}}


这里,由于需要使用的新内容替换掉老的内容,

所以,需要使用 outerHTML 拿到全部内容


再结合不同模板写法的优先级逻辑:

// src/init.js
Vue.prototype.$mount = function (el) { const vm = this; const opts = vm.$options; el = document.querySelector(el); vm.$el = el;
// 如果没有 render, 找 template if (!opts.render) { // 如果没有 template, 采用元素中的内容 const template = opts.template; if (!template) { // 拿到整个元素标签 console.log(el.outerHTML); } }}
复制代码


运行查看结果:




四,将模板编译为 ast 语法树

1,compileToFunction


在 vue 中,编译阶段的最终结果是输出 render 函数:


  1. parserHTML:将模板内容编译为 ast 语法树

  2. generate:再根据 ast 语法树生成为 render 函数;


//  src/compiler/index.js
export function compileToFunction(template) { // 1,将模板变成 AST 语法树 let ast = parserHTML(template); // 2,使用 AST 生成 render 函数 let code = generate(ast);}
function parserHTML(template) { console.log("parserHTML-template : " + template)}
function generate(ast) { console.log("parserHTML-ast : " + ast)}
复制代码

在 Vue 中,compileToFunction 方法是 Vue 编译的入口,

完成了以上两个操作,最终将模板编译成为 render 函数;

2,parserHTML


parserHTML 方法:将 HTML 模板编译成为 ast 语法树

注意:这里的 template 指的是 <template> 标签内部的内容,不包含 <template> 标签


compileToFunction(template) 方法,对 html 模板进行处理,需要传入 html 模板:

<body>  <div id=app>{{message}}</div>  <script>    let vm = new Vue({      el: '#app',      data() {        return { message:"Hello Vue" }      },      template:'<div id="app">{{message}}</div>'    });   </script></body>
复制代码


在 Vue 初始化时:

  • 如果 options 选项中设置了 template,将优先使用 template 内容作为模板: <div id="app"></div>

  • 如果 options 选项没有设置 template,将采用元素内容作为 Html 模板


代码实现

Vue.prototype.$mount = function (el) {  const vm = this;  const opts = vm.$options;  el = document.querySelector(el); // 获取真实的元素  vm.$el = el; // vm.$el 表示当前页面上的真实元素
// 如果没有 render, 看 template if (!opts.render) { // 如果没有 template, 采用元素内容 let template = opts.template; console.log("template = " + template) if (!template) { // 拿到整个元素标签 console.log("没有template, el.outerHTML = " + el.outerHTML) // 将模板编译为 render 函数 template = el.outerHTML; }else{ console.log("有template = " + template) } let render = compileToFunction(template); opts.render = render; }}
复制代码


运行测试:


至此,我们就拿到了 html 模板


将 html 模板编译为 ast 语法树,用 js 对象的树形结构来描述 HTML 语法

这里就需要对 html 模板进行解析,而解析的方式就是使用正则不断匹配和处理

3,render 函数的重要性


有了 render 函数,当数据变化时,就可以通过 render 函数进行新老对比,

从而可以根据最终对比的结果,再对真实 dom 进行更新


五,结尾


又成功水了一篇,还剩 9 篇


本篇,主要介绍了生成 ast 语法树 - 流程说明,涉及以下几个点:


  • Vue 核心渲染流程回顾

  • 三种模板写法及优先级

  • 两种数据挂载方式

  • Vue 的原型方法 $mount

  • compileToFunction -> parserHTM 流程说明


下一篇,生成 ast 语法树-正则说明

用户头像

Brave

关注

还未添加个人签名 2018.12.13 加入

还未添加个人简介

评论

发布
暂无评论
【Vue2.x 源码学习】第十二篇 - 生成 ast 语法树-流程说明