【Vue2】 1. 简单文本渲染

195 阅读2分钟

概述

正常情况下,使用 js 渲染简单的文本步骤为:

也就是我们常常的手动操作 DOM,那 Vue 中是如何渲染文本的呢?

在 Vue 中有一个虚拟 DOM 的概念,Vue 首先会将需要渲染的内容先使用 JS 生成一个虚拟的 DOM 结构,然后再将虚拟 DOM 渲染为真实的 DOM 。

那这会有两个问题:

  1. 什么是虚拟 DOM?
  2. 为什么需要引入虚拟 DOM ?
  3. 虚拟 DOM 是怎么渲染为真实 DOM ?

实现代码 github 地址, 入口文件为 main.js, 源码放在 src目录中,实现一共 110 行代码

DEMO展示

代码:

import Vue from './src/vue'

new Vue({
  el: '#app',
  data() {
    return { message: '简单文本渲染' }
  },
  render(h) {
    return h('div', null, this.message)
  }
})

效果:

实现一个最简单的文本渲染,主要包含:

  1. 初始化一个Vue实例
  2. 引用 data 中属性 message
  3. 渲染文本

过程解析

  1. VNode也就是对真实Dom节点的一种表示方式,VDom也就是一系列的VNode
  2. 渲染阶段,会递归遍历 VNode,根据VNode的类型结合 DOM Api 进行Dom操作

核心代码

  1. Vue的构造函数:
    class Vue {
        constructor(options) {
            this.$options = options
            this.initData()
            this.mount()
        }
        initData(){}
        mount() {}
    }
    
  2. 属性代理, 将data中的定义的属性代理到Vue的实例上面去,中间会有一个 data -> vm._data 过程,通过 vm.xxx 获取时,会读取 vm._data[xxx] 的值:
    initData() {
         let data = this.$options.data
         data = this._data = typeof data === 'function' ? data.call(this, this) : (data || {})
         const keys = Object.keys(data)
         for (let key of keys) {
           if (!isReserved(key)) {
             proxy(this, '_data', key)
           }
         }
     }
     function proxy(target, sourceKey, key) {
         const definition = {
           enumerable: true,
           configurable: true,
           get: function () { return this[sourceKey][key] },
           set: function (val) { this[sourceKey][key] = val }
         }
         Object.defineProperty(target, key, definition);
     }
    
  3. 生成VNode的过程,也就是使用一个 JS 的 Object 来描述一个DOM节点,其中包含一些属性以及数据:
    class VNode {
        constructor(tag, data, children, text, elm, context) {
            this.tag = tag
            this.data = data
            this.children = children
            this.text = text
            this.elm = elm
        }
    }
    
  4. 由VNode转化为真实DOM过程, 也就是patch的过程,首次渲染需要是需要删除 #app 元素 (也就是初始化传入的el):
    function patch($el, vnode) {
        // 创建元素
        createElm(vnode, document.parentNode($el), document.nextSibling($el))
        // 删除 #app
        removeElm(document.parentNode($el), $el)
    }
    

总结

文本渲染,通常我们的做法是:直接通过DOM提供的API进行操作。 而Vue中加了一个先生成VNode的过程,然后再借助 DOM 原生的API进行操作。