看点:vue学习之聊聊模板编译原理

时间:2023-03-07 19:14:16       来源:转载

什么是模板编译?下面本篇文章带大家聊聊vue中的模板编译,探讨一下模板编译原理,希望对大家有所帮助!

vue提供了模板语法,允许我们声明式地描述状态和DOM之间的绑定关系,比如

{{name}}

模板编译指的是模板将编译成render函数的过程,渲染函数的作用是每次执行时,会根据最新状态生成新的vnode


【资料图】

编译的过程是:模板作为输入 -> 模板编译 阶段->生成 渲染函数

面试题

vue的模板编译?模板编译Compiler中render讲解?vue 模板编译的过程,每一个过程细说一下做了些什么模板编译,谁去解析AST树 【相关推荐:vuejs视频教程、web前端开发】

将模板编译成渲染函数

解析器:将模板解析为AST(Abstract Syntax Tree 抽象语法树)优化器:遍历AST标记静态节点,因为静态节点不可变,不需要为打上标签的静态节点创建新的虚拟节点,直接克隆已有的虚拟节点。代码生成器:使用AST生成渲染函数。将AST转换成代码字符串。将代码字符串放入渲染函数中,导出被外界使用。

案例

1.模板确认

假设如下代码,有eltemplaterender$mount

//复杂案例let vue = new Vue({    el: "#app",    data() {        return {            a: 1,            b: [1]        }    },    render(h) {        return h("div", { id: "hhh" }, "hello")    },    template: ``}).$mount("#app")console.log(vue)//脚手架创建的案例let vue = new Vue({  render: h => h(App)}).$mount("#app")
登录后复制

1)渲染到哪个根节点上:判断有无el属性,有的话直接获取el根节点,没有的话调用$mount时去获取根节点

2)渲染哪个模板到根节点上去:是否调用render函数传入了模板 render: h => h(App) ->

有render:这时候优先执行render函数,render优先级 > template无render:有template:template解析成render函数的所需格式-代码字符串,并使用调用render函数渲染无template:el根节点的outerHTML解析成render函数的所需格式-代码字符串,并使用调用render函数渲染 3.渲染的方式:无论什么情况,最后都统一是要使用render函数渲染

2.解析器-将模板解析成AST

解析器-将模板解析成AST

{{name}}

登录后复制

将上述模板解析成AST后,AST抽象语法树就是使用JS中的对象来描述一个节点,一个对象表示一个节点。

{  tag: "div"  type: 1, //节点类型  staticRoot: false,  static: false,  plain: true,  parent: undefined, //存放父节点  attrsList: [],  attrsMap: {},  children: [ //存放孩子节点      {      tag: "p"      type: 1,      staticRoot: false,      static: false,      plain: true,      parent: {tag: "div", ...},      attrsList: [],      attrsMap: {},      children: [{          type: 2,          text: "{{name}}",          static: false,          expression: "_s(name)"      }]    }  ]}
登录后复制

解析器的工作原理

解析器的原理的是一小段一小段地截取模板字符串,每截取一小段字符串,就会根据截取出来的字符串类型触发不同的钩子函数,直到模板字符串截空停止。然后使用栈来确定层级关系

解析器内部分也分几个子解析器,如HTML解析器、文本解析器等。

HTML解析器的作用是解析HTML,在解析HTML的过程中不断触发各种钩子函数,

开始标签的钩子函数中可以构建元素类型的节点文本钩子函数中可以构建文本类型的节点注释钩子函数中可以构建注释类型的节点结束标签钩子函数

文本解析器是对HTML解析出来的文本进行二次加工,比如插值语法{{}}

如何确定DOM之间的层级关系?使用栈在触发开始标签的钩子函数时,如果当前标签不是自闭合标签,就pushstack。 在触发结束标签的钩子函数时,就从栈中pop出战

3.优化器-标记AST中的静态节点

标记静态子树的好处

每次重新渲染时,不需要为静态子树创建新虚拟子树,克隆已存在的静态子树在虚拟DOM中打补丁(patching)的过程可以跳过 ,静态子树是不可变的

优化器的内部实现主要分两步用递归的方式将所有节点添加 static 属性,true表示是静态的,false表示不是静态的。

在AST中找出所有静态节点并打上标记静态节点:DOM不会发生变化的节点 通过递归的方式从上向下标记静态节点,如果一个节点被标记为静态节点,但它的子节点却被标记为动态节点,就说明该节点不是静态节点,可以将它改为动态节点。静态节点的特征是它的子节点也必须是静态的。**在AST中找出所有静态根节点并打上标记 ** 静态根节点:子节点全是静态节点的节点 使用递归从上向下寻找,在寻找的过程中遇见的第一个静态节点就为静态根节点,同时不继续往下找。

怎么判断是否静态节点?在将模板字符串解析成AST的时候,会根据不同的文本类型设置一个 type

type说明是否时静态节点
1元素节点进行一些排除
2带遍历的动态文本节点不是
3不带遍历的纯文本节点

4.代码生成器-将AST转化成渲染函数中的代码字符串

代码生成器的作用:将AST转化成渲染函数中的代码字符串

{{name}}

//生成的render渲染函数{ render: `with(this){return _c("div",[_c("p",[_v(_s(name))])])}`}//格式化后with(this){ return _c( "div", [ _c( "p", [ _v(_s(name)) ] ) ] )}
登录后复制

生成代码字符串是一个递归的过程,从顶向下依次处理每一个AST节点。 节点有三种类型,分别对应三种不同的创建方法与别名。

类型创建方法别名
元素节点createElement_c
文本节点createTextVNode_v
注释节点createEmptyVNode_e

渲染函数可以生成VNode的原因:渲染函数其实是执行了createElement,而createElement可以创建VNode。

代码字符串的拼接过程

递归AST来生成字符串,最先生成根节点,然后在子节点字符串生成后,将其拼接在根节点的参数中,子节点的子节点拼接在子节点的参数中,一层层拼接。

(学习视频分享:vuejs入门教程、编程基础视频)

以上就是vue学习之聊聊模板编译原理的详细内容,更多请关注php中文网其它相关文章!

关键词: