Vue中的数据操作

210 阅读3分钟

新的一年开始了,决定开始记录一下学习工作中遇到的问题,可能很简单,就当是作为自己的一个小小的积累沉淀吧。

Vue中如何实现响应式

我们一开始在Vue的data选项中添加的数据是不可响应式的普通对象。

通过Observer类中的walk遍历执行defineReactive方法给普通的对象属性添加getter、setter。

defineReactive本质是执行了Object.defineProperty()方法。

Object.defineProperty(obj, prop, descriptor)方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象。

在defineReactive中会实例化Dep方法,会在对象属性getter时候收集依赖关系,在setter的时候派发更新通知dep.notify()

每个组件实例都对应一个watcher实例,在组件渲染的时候把涉及到的数据记录为依赖,之后当依赖项的setter触发时,会通知watcher,从而使它关联的组件重新渲染。

Data

data项必须是纯粹的对象。 并且当一个组件被定义时,data必须声明返回一个初始数据对象的函数,防止组件在多个实例中引用同一个数据对象。 否则:...

所以我们要做到每个组件实例使用独立的数据对象。

data(){
    return {}
}

Computed和Watch的区别

Computed:

data: {
    name: 'greatjiang',
    age: 18
},
computed:{
    information() {
        return `My name is ${this.name},I am ${this.age} years old.`
    }
}

对于复杂的逻辑,需要依赖其它属性要使用Computed。计算属性是根据响应式依赖进行缓存的。响应依赖没有改变的情况下是不会重新求值的。

Watch:

data:{
    name: 'greatjiang'
},
watch:{
    name(newVal, oldVal) {
        this.doSomething()
    }
}

watch可以在数据变化时做出响应,不会缓存。只要watch数据有变化,就会立即执行。

Vm.$set

当你在初始数据对象中直接添加新属性时,这样的属性值是不具备响应式的。

data(){
    return {
        information:{
            name : 'greatjiang',
            age:18
        }
    }
}
this.information.hobby = 'badminton'

这个时候不会响应式的展示在组件上。

对于初始的时候对象所不具备的属性,我们需要调用$set()追加响应式属性。

    Vm.$set(this.information,'hobby','badminton')。

这样就可以在组件上响应式的显示了。

PS:不可以在data根上添加动态响应式属性!!!

set方法其实也是通过defineReactive劫持数据,然后调用notify通知watcher更新。

数组数据操作

你可能会发现在Vue中使用对数组做添加(push/unshift)、删除(pop/shift)、排序(sort)、反转(reverse)、截取(splice)操作后数组是响应式变化的。 以至于你想当然的这么操作

data(){
    Return {
        list: [0,2,3]
    }
}
this.list[0] = 1

这种操作后是不会响应式的更新数据的。 可以通过splice操作实现。

this.list.splice(0,1,1)

那么为什么会是这样的呢?

因为上述所列举的方法其实是Vue进行了包装,(源码/src/core/observer/array.js),数据变化时会触发更新通知dep.notify()。相比之下没有封装过的filter()、concat()和slice()的原始数组方法不会响应数组的变化。

Ending

我觉得还是应该多多参与掘金社区讨论,在这里看着大佬们分享的文章学到了很多知识,也解决了很多工作中遇到的坑。祝大家新年快乐,永不脱发!