Skip to content

awspi/mini-vue

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MINI_VUE

vue最简实现

☑️完成笔记

代码实现

  • ✅reactivity
    • reactive
    • ref
    • effect
    • computed
  • ✅runtime
    • h()
    • render()
    • createApp()
    • nextTick()
  • ✅compiler
    • parse()
    • compile()

reactivity

VUE2监听对象的变化通过 是通过Object.defineProperty的方式

VUE3使用Proxy+Reflect实现

runtime

compiler

编译的中间产物

了解compiler的工作流程,一步步最终实现compiler部分

image-20220829232135906

模板代码

就是一段字符串,通过解析 parse 转换为原始 AST 抽象语法树。

//例如
const tem=`<div id="foo" v-if="ok">hello {{name}}</div>`

AST

指抽象语法树

例如

<div id="foo" v-if="ok">hello {{name}}</div>

转化结果⬇️

{
  "type": "ROOT",
  "children": [
    {
      "type": "ELEMENT",
      "tag": "div",
      "tagType": "ELEMENT",
      "props": [
        {
          "type": "ATTRIBUTE",
          "name": "id",
          "value": { "type": "TEXT", "content": "foo" }
        }
      ],
      "directives": [
        {
          "type": "DIRECTIVE",
          "name": "if",
          "exp": {
            "type": "SIMPLE_EXPRESSION",
            "content": "ok",
            "isStatic": false
          }
        }
      ],
      "isSelfClosing": false,
      "children": [
        { "type": "TEXT", "content": "hello " },
        {
          "type": "INTERPOLATION",
          "content": {
            "type": "SIMPLE_EXPRESSION",
            "isStatic": false,
            "content": "name"
          }
        }
      ]
    }
  ]
}

image-20220829234014176

AST Node 的类型

export const NodeTypes = {
  ROOT: 'ROOT',//根节点
  ELEMENT: 'ELEMENT',//元素节点
  TEXT: 'TEXT',//文本节点
  SIMPLE_EXPRESSION: 'SIMPLE_EXPRESSION',//minivue只实现表达式
  INTERPOLATION: 'INTERPOLATION',//插值节点
  ATTRIBUTE: 'ATTRIBUTE',//属性节点
  DIRECTIVE: 'DIRECTIVE',//指令节点
};
//元素类型
const ElementTypes = {
  ELEMENT: 'ELEMENT',//元素
  COMPONENT: 'COMPONENT',//组件
};

AST Node最终转换结果

  1. 根节点
{
  type: NodeTypes.ROOT,
  children: [],
}
  1. 纯文本节点
{
  type: NodeTypes.TEXT,
  content: string
}
  1. 表达式节点
{
  type: NodeTypes.SIMPLE_EXPRESSION,
  content: string,
  // 表达式是否静态。静态可以理解为content就是一段字符串;而动态的content指的是一个变量,或一段js表达式
  isStatic: boolean,
}
  1. 插值节点
{
  type: NodeTypes.INTERPOLATION,
  content: {
    type: NodeTypes.SIMPLE_EXPRESSION,
    content: string,
    isStatic: false,
  } // 表达式节点
}
  1. 元素节点
{
  type: NodeTypes.ELEMENT,
  tag: string, // 标签名,
  tagType: ElementTypes, // 是组件还是原生元素,
  props: [], // 属性节点数组,
  directives: [], // 指令数组
  isSelfClosing: boolean, // 是否是自闭合标签,
  children: [],
}
  1. 属性节点
{
  type: NodeTypes.ATTRIBUTE,
  name: string,
  value: undefined | {
    type: NodeTypes.TEXT,
    content: string,
  } // 纯文本节点
}
  1. 指令节点
{
  type: NodeTypes.DIRECTIVE,
  name: string,
  exp: undefined | {
    type: NodeTypes.SIMPLE_EXPRESSION,
    content: string,
    isStatic: false,
  }, // 表达式节点
  arg: undefined | {
    type: NodeTypes.SIMPLE_EXPRESSION,
    content: string,
    isStatic: true,
  } // 表达式节点
}

Code

codegen生成的函数代码

例如

<div id="foo" v-if="ok">hello {{name}}</div>

经过prase+transform+codegen之后生成的代码code⬇️

with (ctx) {
  const { h, Text, Fragment, renderList, withModel, resolveComponent } =
    MiniVue;
  return ok
    ? h("div", { id: "foo" }, [h(Text, null, "hello "), h(Text, null, name)])
    : h(Text, null, "");
}

编译的关键函数

parse

原始的模板代码通过解析 parse 转换为原始 AST 抽象语法树。

transfrom

codegen(code generate)

遍历 codegenNode,递归地生成最终的渲染函数代码。

AST 到渲染函数代码,vue 经过了 transform, codegen 两个步骤。vuetransform 太复杂了将这两个步骤合而为一

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published