set
Vue.set、vm.$set 都指向了内部的 set 方法。它们的功能是向响应式对象中添加属性,并确保这个对象是响应式的,且触发视图更新。它必须用于向响应式对象添加新属性,因为 Vue 无法探测普通的新增属性(比如 this.myObject.newProperty = ‘hi’)
注意:传入的对象不能是 Vue 实例,或者 Vue 实例的根数据对象(比如 Vue.$data)。
vm.$set(obj, 'foo', 'test')
定义位置
Vue.set()
- global-api/index.js
// 静态方法 set/delete/nextTick
Vue.set = set
Vue.delete = del
Vue.nextTick = nextTick
- global-api/index.js
vm.$set()
- instance/index.js
// 注册 vm 的 $data/$props/$set/$delete/$watch
// instance/state.js
stateMixin(Vue)
// instance/state.js
Vue.prototype.$set = set
Vue.prototype.$delete = del
- instance/index.js
源码
- set() 方法
- observer/index.js ```javascript /**
- Set a property on an object. Adds the new property and
- triggers change notification if the property doesn’t
- already exist.
*/
export function set (target: Array
| Object, key: any, val: any): any { if (process.env.NODEENV !== ‘production’ && (isUndef(target) || isPrimitive(target)) ) { warn( Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}
) } // 判断 target 是否是对象,key 是否是合法的索引 if (Array.isArray(target) && isValidArrayIndex(key)) { target.length = Math.max(target.length, key) // 通过 splice 对key位置的元素进行替换 // splice 在 array.js 进行了响应化的处理 target.splice(key, 1, val) return val } // 如果 key 在对象中已经存在直接赋值 if (key in target && !(key in Object.prototype)) { target[key] = val return val } // 获取 target 中的 observer 对象 const ob = (target: any)._ob // 如果 target 是 vue 实例或者 $data 直接返回 if (target._isVue || (ob && ob.vmCount)) { process.env.NODE_ENV !== ‘production’ && warn( ‘Avoid adding reactive properties to a Vue instance or its root $data ‘ + ‘at runtime - declare it upfront in the data option.’ ) return val } // 如果 ob 不存在,target 不是响应式对象直接赋值 if (!ob) { target[key] = val return val } // 把 key 设置为响应式属性 defineReactive(ob.value, key, val) // 发送通知 ob.dep.notify() return val } ```
del
Vue.delete、vm.$delete 都指向了内部的 del 方法。它们的功能是删除对象的属性,确保删除能触发更新视图。这个方法主要用于避开 Vue 不能检测到属性被删除的限制。
注意:传入的对象不能是 Vue 实例,或者 Vue 实例的根数据对象(比如 Vue.$data)。
vm.$delete(vm.obj, 'msg')
vm.$delete(vm.arr, 0) // 删除数组中的第一个元素
定义位置
Vue.delete()
- global-api/index.js
// 静态方法 set/delete/nextTick
Vue.set = set
Vue.delete = del
Vue.nextTick = nextTick
- global-api/index.js
vm.$delete()
- instance/index.js
// 注册 vm 的 $data/$props/$set/$delete/$watch
stateMixin(Vue)
// instance/state.js
Vue.prototype.$set = set
Vue.prototype.$delete = del
- instance/index.js
源码
- src\core\observer\index.js
/**
* Delete a property and trigger change if necessary.
*/
export function del (target: Array<any> | Object, key: any) {
if (process.env.NODE_ENV !== 'production' &&
(isUndef(target) || isPrimitive(target))
) {
warn(`Cannot delete reactive property on undefined, null, or primitive value: ${(target: any)}`)
}
// 判断是否是数组,以及 key 是否合法
if (Array.isArray(target) && isValidArrayIndex(key)) {
// 如果是数组通过 splice 删除
// splice 做过响应式处理
target.splice(key, 1)
return
}
// 获取 target 的 ob 对象
const ob = (target: any).__ob__
// target 如果是 Vue 实例或者 $data 对象,直接返回
if (target._isVue || (ob && ob.vmCount)) {
process.env.NODE_ENV !== 'production' && warn(
'Avoid deleting properties on a Vue instance or its root $data ' +
'- just set it to null.'
)
return
}
// 如果 target 对象没有 key 属性直接返回
if (!hasOwn(target, key)) {
return
}
// 删除属性
delete target[key]
if (!ob) {
return
}
// 通过 ob 发送通知
ob.dep.notify()
}