说明

  • Vue 版本:2.5.13

正文

先来看看 Vue 的配置,以组件为例

{
    render(h) {
        
    },
    props: {
        props1: Number
    },
    data() {
        return {
            data1: 1,
            data2: 0
        }
    },
    computed: {
        computed1() {
            return this.data1 +  this.props1
        }
    },
    watch: {
        computed1(newValue) {
            setTimeout(()=>{
                console.log(newValue)
            },0)
        }
    }
}

响应式实现过程大概可以分为三块:

数据 Data

初始化 data、props、computed 时(初始化 render 时还有一些其他内置属性),通过 Object.defineProperty 将属性定义成 getset,并为每个属性绑定一个 Dep 实例。

详见 src/core/instance/state.jsinitDatainitProps

组件 Component

可以把整个 Vue 应用认为是大大小小的组件堆砌而成。Vue 为每个组件都定义了两块重要的内容:Watcher 和 Render。

执行 $mount 时调用 mountComponent、初始化 watch、computed时、调用实例方法 $watch时,都会给实例化一个 Watcher。而 Watcher 初始化时会进行一次求值(执行实例中的 getter 方法),首先会将当前实例设置为 Dep 当前目标,然后触发数据的相关属性的 get 方法。

详见 src/core/instance/state.jsinitComputedinitWatch

依赖 Dep

Dep 类就是用来关联数据与组件的 Watcher 的。

// the current target watcher being evaluated.
// this is globally unique because there could be only one
// watcher being evaluated at any time.
Dep.target = null

其实初始化 Watcher 时,通过执行了对应属性的 get 方法,将Watcher 实例放入数据对应的 Dep 实例的订阅列表中。而当数据发生变化时,对应属性执行 set 方法,会通知到对应的 Dep 实例,再通知订阅列表中的 Watcher。

此时,Watcher 将通知组件执行 Render,重新计算出新的 VNode,通过新旧 VNode 的对比,进行视图更新。


siwuxie
528 声望67 粉丝

404