实现 VUE 中 MVVM - step2 - Dep

栏目: 编程工具 · 发布时间: 5年前

内容简介:在上一篇我们大概实现了,首先我们可以先确定这个类下的属性,以及一些功能:类下属性:

在上一篇我们大概实现了, Vue 中的依赖收集和触发,但我们仅仅是将依赖维护在一个内置数组中,这样做虽然容易理解,但毕竟不好维护,为了更容易的维护这些依赖,我们来实现一个维护依赖的类。

确定功能

首先我们可以先确定这个类下的属性,以及一些功能:

类下属性:

  • target 函数,用于存放需要添加的依赖

实例下属性及方法:

  • subs/Array 用于存放依赖
  • addSub/Function 用于添加依赖
  • removeSub/Function 用于移除依赖
  • notify/Function 用于执行依赖

实现

考虑到直接放在浏览器上执行,所以直接用 ES5 的类写法。

let Dep = function(){

    // 实例属性
    this.subs = []
    
    // 实例方法
    this.addSub = function(sub){
        this.subs.push(sub)
    }
    
    this.removeSub = function(sub){
        const index = this.subs.indexOf(item)
        if (index > -1) {
            this.subs.splice(index, 1)
        }
    }
    
    this.notify = function(newValue, oldVaule){
        this.subs.forEach(fnc=>fnc(newValue, oldVaule))
    }
}

// 类属性
Dep.target = null
复制代码

好了,现在我们拥有了一个管理依赖的类(这里将依赖简化为一个方法),现在我们就可以动手来改一下之前的代码了。

let defineReactive = function(object, key, value){
    let dep = new Dep()
    Object.defineProperty(object, key, {
        configurable: true,
        enumerable: true,
        get: function(){
            if(Dep.target){
                dep.addSub(Dep.target)
            }
            return value
        },
        set: function(newValue){
            if(newValue != value){
                dep.notify(newValue, value)
            }
            value = newValue
        }
    })
}
复制代码

可以发现,之前我们用来存放依赖的数组变成了一个依赖管理( Dep )的实例。同样的,在取值时收集依赖,在设置值(当值发生变化)时触发依赖。

由于依赖的处理由 Dep 的实例管理了,这里仅仅调用一下相关方法即可。

接下来试一试效果:

let object = {}
defineReactive(object, 'test', 'test')
Dep.target = function(newValue, oldValue){
    console.log('我被添加进去了,新的值是:' + newValue)
}
object.test
// test

Dep.target = null
object.test = 'test2'
// 我被添加进去了,新的值是:test2

Dep.target = function(newValue, oldValue){
    console.log('添加第二个函数,新的值是:' + newValue)
}
object.test
// test

Dep.target = null
object.test = 'test3'
// 我被添加进去了,新的值是:test3
// 添加第二个函数,新的值是:test3
复制代码

但是上面的代码暴露了几个问题

  1. Dep 这个类将监听属性和处理依赖进行了解耦,但是却没有完全解耦,在触发依赖的时候,还是得传新旧值。
  2. 上面代码中 Dep 中定义的 removeSub 在代码中并没有用到,因为 Dep 的实例是在 defineReactive 函数的作用域中,外部并不能直接调用,而删除依赖肯定是在外部的环境中,也就是说即使我们将代码改成这样,我们还是不能直接取删除已经没用的依赖。

Vue 中实现了一个 Watcher 的类来处理以上两个问题,之后再说。

以下 ES6 语法下的 DepVue 源码中差不多就这样

class Dep {

    constructor() {
        this.subs = []
    }

    addSub(sub) {
        this.subs.push(sub)
    }

    removeSub(sub) {
        const index = this.subs.indexOf(item)
        if (index > -1) {
            this.subs.splice(index, 1)
        }
    }

    notify() {
        this.subs.forEach(fnc=>fnc(oldValue, newValue))
    }
}

Dep.target = null
复制代码

点击查看相关代码


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web Development Recipes

Web Development Recipes

Brian P. Hogan、Chris Warren、Mike Weber、Chris Johnson、Aaron Godin / Pragmatic Bookshelf / 2012-1-22 / USD 35.00

You'll see a full spectrum of cutting-edge web development techniques, from UI and eye candy recipes to solutions for data analysis, testing, and web hosting. Make buttons and content stand out with s......一起来看看 《Web Development Recipes》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

SHA 加密
SHA 加密

SHA 加密工具

html转js在线工具
html转js在线工具

html转js在线工具