vue中Vue.set()的使用以及对其进行深入解析
Vue.set()使用
vue 在实例上添加新的属性的时候,该属性,并不是响应式的。同样删除某一属性的时候,也不会实时渲染到页面上。
比如:
<p> 年龄:{{obj.age? obj.age: "无"}}</p>
···········
data() {
return {
obj:{ name:"Lena", id:1 },
}
}
页面上 显示的是 年龄:无 现在需要添加一个响应式的属性 age 。
<template>
<div class="app">
<ul>
<li> 年龄:{{obj.age? obj.age: "无"}}</li>
</ul>
<button @click="add()">添加年龄属性</button>
<button @click="show()">打印</button>
</div>
</template>
<script>
import Vue from 'vue'
export default {
component:{},
data() {
return {
obj:{ name:"Lena", id:1 },
}
},
methods: {
add(){
this.obj.age= 20
},
show(){
console.log('obj',this.obj)
}
}
}
</script>
效果:
通过 this.obj.age= 20 ,控制台打印已经有了该属性,并没有渲染到页面上。 可见,这种方式添加的属性 age 并不是响应式的。
使用Vue.set() ,更改add()方法:
add(){
Vue.set(this.obj,'age', '20')
},
效果:
因为vue不能检测到对象属性的添加或者删除,只有在data对象上存在的属性是响应式的,所以要使用Vue.set()方法将响应式属性添加到对象上。同样的道理,删除对象 Vue.delete也是如此。
Vue.delete()的使用
<template>
<div class="app">
<ul>
<li> 年龄:{{obj.age? obj.age: "无"}}</li>
</ul>
<button @click="add()">添加年龄属性</button>
<button @click="del()">删除年龄属性</button>
<button @click="show()">打印</button>
</div>
</template>
<script>
import Vue from 'vue'
export default {
component:{
},
data() {
return {
obj:{ name:"Lena", id:1 },
}
},
methods: {
add(){
Vue.set(this.obj,'age', '20')
},
del(){
Vue.delete(this.obj,'age')
},
show(){
console.log('obj',this.obj)
}
}
}
</script>
效果:
del() 方法如果是下面两种,同样不是响应式的。
del(){
delete this.obj.age
},
或者:
del(){
this.obj = { name:"Lena", id:1 }
},
Vue.set()方法原理解析
我们找到封装set方法的地方:.........\node_modules\vue\class="lazy" data-src\core\observer\index.js
找到封装的set方法:
export function set (target: Array<any> | Object, key: any, val: any): any {
if (process.env.NODE_ENV !== 'production' &&
(isUndef(target) || isPrimitive(target))
) {
warn(`Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}`)
}
if (Array.isArray(target) && isValidArrayIndex(key)) {
target.length = Math.max(target.length, key)
target.splice(key, 1, val)
return val
}
if (key in target && !(key in Object.prototype)) {
target[key] = val
return val
}
const ob = (target: any).__ob__
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
}
if (!ob) {
target[key] = val
return val
}
defineReactive(ob.value, key, val)
ob.dep.notify()
return val
}
对象调用:Vue.set( target ,'age', 20 )
数组调用:Vue.set( array , 0, 20 ) //数组对象,索引,值
首先是判断是否是开发环境并且 对象是否被定义isUndef(target)或者是否是基础类型isPrimitive(target),否则会报错:
`Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}`
if (process.env.NODE_ENV !== 'production' &&
(isUndef(target) || isPrimitive(target))
)
如果是数组的话,调用重写的splice()方法,可以更新视图。
isValidArrayIndex(key)方法用来验证是否是一个有效的数组索引, 其实就是验证是否是一个非无穷大的正整数。
if (Array.isArray(target) && isValidArrayIndex(key)) {
target.length = Math.max(target.length, key)
target.splice(key, 1, val)
return val
}
如果对象本身就有所要添加的属性,那只需要直接赋值就可以。
if (key in target && !(key in Object.prototype)) {
target[key] = val
return val
}
如果是Vue实例,或者是根数据data的时候,就会报错。
如果本身就不是响应式的,只需要直接赋值即可。
const ob = (target: any).__ob__
//如果是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
}
//如果本身就不是响应式的,只需要直接赋值即可。
if (!ob) {
target[key] = val
return val
}
defineReactive(ob.value, key, val)
ob.dep.notify()
return val
排除各种不合适的,最后给当前对象定义一个属性:defineReactive(ob.value, key, val) 相当于用了 Object.defineProperty 重新定义了一下。
最后,手动通知视图更新:ob.dep.notify()
总结
这个 set方法,对于数组来说,调用的就是splice,对于对象来说,使用的就是defineReactive,再添加了一个手动的视图更新。这就是set的原理。
到此这篇关于vue中Vue.set()的使用以及对其进行深入解析的文章就介绍到这了,更多相关vue Vue.set()的使用内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341