前言
本章项目地址
- 主讲$set
- vue的data里边声明或者已经赋值过的对象或者数组(数组里边的值是对象)时, 不会更新视图
这个时候可以使用
$set(删除可以用$del)
- 其实每个对象或者数组, 都加了个dep, 在数据劫持时, 对数据的值也要进行劫持(递归劫持数据),
如果是对象或者数据 将返回本身的
Observer实例 再在getter中, 如果返回有数据, 让对象或 者数组dep收集watcher
- 如果添加了数据 就会通知
target.__ob__.dep.notify更新视图
- 数组的添加和删除用的都是
splice方法
$set和$del源码
示例
<div id="app">
{{obj}} - {{arr}}
</div>
<script>
var vm = new Vue({
data: {
obj: {n: 1},
arr: [0]
},
})
vm.$mount('#app')
setTimeout(() => {
vm.$set(vm.obj, 'xxxx', 123456)
vm.$set(vm.arr, 1, 100)
}, 2000)
</script>


正题
$set和$del方法
import { set, del } from './observer/index'
Vue.prototype.$set = set
Vue.prototype.$del = del
export function set(target, key, value) {
if (Array.isArray(target)) {
target.length = Math.max(target.length, key)
target.splice(key, 1, value)
return value
}
if (target.hasOwnProperty(key)) {
target[key] = value
return value
}
const ob = target.__ob__
if (!ob) {
target[key] = value
return value
}
defineReactive(ob.value, key, value)
ob.dep.notify()
return value
}
export function del (target, key) {
if (Array.isArray(target)) {
target.splice(key, 1)
return
}
const ob = target.__ob__
if (!target.hasOwnProperty(key)) return
delete target[key]
if (!ob) return
ob.dep.notify()
}
observe
class Observer {
constructor(data) {
this.value = data
this.dep = new Dep()
Object.defineProperty(data, '__ob__', {
value: this,
enumerable: false
})
}
function defineReactive(data, key, value) {
let childOb = observe(value)
let dep = new Dep()
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
get() {
if (Dep.target) {
dep.depend()
if (childOb) {
childOb.dep.depend()
if (Array.isArray(value)) { dependArray(value) }
}
}
return value
},
set(newValue) {
if (newValue !== value) {
observe(newValue)
value = newValue
dep.notify()
}
}
})
}
export function observe(data) {
if (!isObject(data)) return
if (data.__ob__) return data.__ob__
return new Observer(data)
}
完