从template---------->渲染函数都干了些什么

<深入浅出Vuejs>模板编译_解析器&优化器&生成器_V1RusCz的博客-CSDN博客 原文链接

在Vue中可以通过{ {变量}}或者在里面写表达式,但是在html中为什么不行呢?在一个篇章中讲过

从:模板---------------->渲染函数------------------>vnode-------------------->视图。

编译模板的主要目的就是生成渲染函数,这个过程主要包含三个部分:

1.将模板字符串解析为AST(抽象语法树)

2.便利AST标记所有的静态节点(不需要重新渲染的节点)

3.使用AST生成渲染函数

以上三步分别对应模板编译中的三个模块:

1.解析器(Html解析器 文本解析器 过滤解析器)

2.优化器

3.代码生成器

让我们从vue.$mount函数开始,分别介绍以上三个模块的具体实现原理

1.解析器

<div>
<p>{
   
   {name}}</p>
</div>

{
  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解析器,在其过程中会触发不同的构造函数(标签开始钩子,标签结束钩子,文本钩子,注释钩子)。

2.优化器

 通过解析器的处理,我们就得到了Vue模板的AST。由于Vue是响应式设计,所以拿到AST之后还需要进行一系列优化,确保静态的数据不会进入虚拟DOM的更新阶段,以此来优化性能。。

简单来讲,就是把静态节点的static属性设置为true,然后找到再便利一次找到静态根节点。

注意:静态节点的所有子节点都是静态节点,动态节点的父节点是动态节点,这个特征保证,我们找到的第一个静态节点会被标记为静态根节点,此时不用再遍历其子节点,因为他的子节点必然是静态节点

  

3.代码生成器

至此,我们已经得到了优化后的AST,我们只需要做一些简单的字符串拼接就能生成Render函数。

export function generate(ast, options) {
  const state = new CodegenState(options)
  const code = ast ? genElement(ast, state) : '_c("div")'
  return {
    render: `with(this){return ${code}}`,
    staticRenderFns: state.staticRenderFns
  }
}
 
export function genElement (el, state) {
  let code
  const data = genData(el, state)
  const children = genChildren(el, state, true)
  code = `_c('${el.tag}'${
    data ? `,${data}` : '' // data
  }${
    children ? `,${children}` : '' // children
  })`
  return code
}

生成的渲染函数效果如图:

<div>
  <h2 v-if="message">{
   
   {message}}</h2>
  <button @click="showName">showName</button>
</div>
with (this) {
    return _c(
      'div',
      [
        (message) ? _c('h2', [_v(_s(message))]) : _e(),
        _v(' '),
        _c('button', { on: { click: showName } }, [_v('showName')])
      ])
    ;
}

注意:

vm._c是创建DOM标签的

vm._v是创建文本节点的

vm._s就是toString

分析用render挂载的实例

import Vue from "vue";
import App from "./App.vue";

Vue.config.productionTip = false;


new Vue({
  render: (h) => h(App),
}).$mount("#app");

render函数是vue通过js渲染dom结构的函数createElement,约定可以简写为h

官方文档中是这样写的,createElement是Vue.js里面的函数。

这个函数的作用就是生成一个VNode节点,

render函数得到这个VNode节点之后

返回给Vue.js的mount函数,渲染成真实DOM节点,并挂载到个根节点上。

render函数跟template一样都是创建html模板的,但是有些场景中用template实现

起来代码冗长繁琐而且有大量重复,这个时候就可以用render函数。

由虚拟节点---------------------------->真实节点的一个过程。

总结:

1.解析器的主要功能就是将模板字符串转换为AST,解析器parse调用parseHtml函数用于循环解析模板字符串,并把不同类型的字符串调用相应的钩子函数(作用是维护层次栈以及建立AST),最终返回AST根节点。

2.优化器用于标记所有静态节点以及静态根节点        

3.代码生成器将优化获得AST转换为渲染函数   

猜你喜欢

转载自blog.csdn.net/qq_59076775/article/details/124397466
今日推荐