Vue原理学习(四)

实现Virtual DOM 的VNode节点

在这里,我们首先要区分Virtual DOM 和VNode的意思,Virtual DOM我之前也介绍过,是虚拟DOM,相信大家也不陌生,而VNode是虚拟节点的意思。好比说JavaScript是由一堆Node节点组成的DOM树。

另外,由于Virtual DOM是抽象的JavaScript对象,所以具备了跨平台能力,因为我们完全可以根据特定规则,去渲染出对应的任意的所需要的对象。

实现一个VNode

在着手编写代码前,我们先看下的JavaScript 节点都包含哪些信息。
hi
这里我写了一个a标签,可以看到,它包含了标签名href属性文本。当然,如果更复杂的一些,还会包含嵌套关系。

所以,我们可以想想,因为VNode是一个真实的DOM 节点的抽象,我们也需要这些参数:标签名、属性、文本、子标签等。

该方法VNode大概在Vue源码中736行,除了我们这里传递的参数外,其还包含了contextcomponentOptionsasyncFactory

class VNode{
  constructor(tag, data, children, text, elm) {
    // tag 标签名
    this.tag = tag
    // data 标签包含的数据信息,如前面的href属性,还有其他的如props等
    this.data = data
    // children 子节点, type:Array
    this.children = children
    // elm 当前虚拟节点对应的真实节点
    this.elm = elm
  }
}

然后我们在看来一个Vue组件。


用刚才的VNode类表示就是如下样子:

new VNode('span', {
  // 指令集合数据
  directives: [
    {
      // v-show 指令
      rawName: 'v-show',
      expression: 'isShow',
      name: 'show',
      value: true
    }
  ],
  // 静态class
  staticClass: 'text'
  // 因为文本节点也是节点,所以我们需要再次new一个VNode
  [ new VNode(undefined, undefined, undefined, 'I am span.')]
})

转换成VNode以后的代码:

{
  tag: 'span',
  data: {
    directives: [
      {
        rawName: 'v-show',
        expression: 'isShow',
        name: 'show',
        value: 'true'
      }
    ],
    staticClass: 'text',
    text: undefined,
    children: [
      {
        tag: undefined,
        data: undefined,
        text: 'I am span.',
        children: undefined
      }
    ]
  }
}

所以我们会发现,如果你的节点嵌套关系足够复杂,这里的VNode也会显得特别庞大。

另外,AST(抽象语法树,Abstract Syntax Tree),也和这个差不多。

进一步封装

通过观察上面的代码,我们可以发现,在创建VNode的过程中,会存在空节点和文本节点,这些节点都是很简单的,不需要一些属性,所以我们可以考虑将创建这两种节点的方法提取出来。

在Vue源码中,也有这两个方法, 分别是createEmptyVNodecreateTextVNode,大概在784-794行左右。

创建空节点

function createEmptyVNode() {
  const node = new VNode();
  node.text = ''
  return node;
}

创建文本节点

function createTextVNode(val) {
  return new VNode(undefined, undefined, undefined, String(val))
}

克隆一个VNode节点

有时候,我们需要一个一摸一样的VNode节点,此时,我们只需要提取出来一个克隆方法即可。

该方法cloneVNode在Vue源码中也存在,大概在802行左右。

function cloneVNode(node) {
  const cloneVNode = new VNode(
    node.tag,
    node.data,
    node.children,
    node.text,
    node.elm
  );
  return cloneVNode;
}

这里克隆节点,除了包含以上属性外,还应该包含如:节点注释、节点key等等。

总结

VNode就是一些虚拟的节点,从而构成了Virtual DOM。并且嵌套关系越深,构建出来的VNode对象也越复杂,这个过程中,由于存在空的节点和文本节点,这两个节点不需要额外的属性,所以我们将创建方法抽取了出来。

你可能感兴趣的:(Vue原理学习(四))