Vue 中的 $.set 方法
Vue.set( target, propertyName/index, value )
-
参数:
- {Object | Array} target
- {string | number} propertyName/index
- {any} value
-
**返回值:**设置的值。
-
用法:
向响应式对象中添加一个 property,并确保这个新 property 同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新 property,因为 Vue 无法探测普通的新增 property (比如
this.myObject.newProperty = 'hi'
)注意:注意对象不能是 Vue 实例,或者 Vue 实例的根数据对象。
<div id="app">
{{ obj.title }}
<hr>
{{ obj.name }}
<hr>
{{ arr }}
</div>
<script src="../../dist/vue.js"></script>
<script>
const vm = new Vue({
el: '#app',
data: {
obj: {
title: 'Hello Vue'
},
arr: [2, 3, 5]
}
});
</script>
如上述代码,需要动态的添加一个 obj.name 属性,并在页面上渲染你出来。如果通过 obj.name = ‘set’ 这种方式是不会渲染的,说明通过这种方式添加的属性并不是响应式的。如果有这种需求可以使用 Set 方法,动态的给一个响应式的对象添加响应式一个响应式的属性。
Vue.set() 或者 vm.$set()
这两个方法是相同的,但是我们一般会使用 vm.$set 这个方法,因为在组件中是很难获取到 Vue 的构造函数的。使用方法如下:
vm.$set(vm.obj, 'name', 'zhangsan')
vm.$set(vm.arr, 0, 100)
源码阅读
/**
* 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<any> | Object, key: any, val: any): any {
if (process.env.NODE_ENV !== 'production' &&
(isUndef(target) || isPrimitive(target))
) {
// 如果是 undefined 或者是 原始值,发出警告
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 直接返回 如果是 $data ob.vmCount 的值应该是 1 其他的应该是 0
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
}
-
当使用 set 给数组添加响应式数据的时候会调用响应式数组的 splice 方法,添加属性并且做响应式处理,并在处理完成之后发送通知。
-
当使用 set 给对象添加响应式数据的时候会调用 defineReactive 方法给属性做响应式处理,并在处理完成之后发送通知。