美文网首页
Vue原理学习(四)

Vue原理学习(四)

作者: IsaacHHH | 来源:发表于2018-05-29 10:31 被阅读74次

    实现Virtual DOM 的VNode节点

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

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

    实现一个VNode

    在着手编写代码前,我们先看下的JavaScript 节点都包含哪些信息。
    <a href="https://baidu.com">hi</a>
    这里我写了一个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组件。

    <template>
      <span class='text' v-show='isShow'>
        I am span.
      </span>
    </template>
    

    用刚才的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原理学习(四)

          本文链接:https://www.haomeiwen.com/subject/vcjojftx.html