1、Vue2.x属性更新
1.1、结果描述:
- 运行后当设置sex属性的时视图更新
- 当设置money属性的时候视图不更新
问题分析:
-
当我们使用vm对象更新userlnfo中初始化就存在的属性时视图会自动触发更新,而当我们对userlnfo内部不存在的属性设置值的时候视图不更新,这是因为Vue2.x底层的数据响应式系统使用的是Object.defineProperty()来实现的
-
Vue在初始化的时候会递归的将data选项中的属性绑定setter和getter,通过两者来观察属性的行为,一旦初始化完成便不会再次执行本操作,所以更改已知属性的时候Vue实例是有感知并执行默认处理行为的,当我们操作对象内部不存在的属性时由于其没有setter和getter,Vue将无法观察到这些属性的赋值和取值,视图更新操作也无法进行。
1.2、解决方案:
1.使用$set()更新后定义的属性
针对Vue2.x底层能力的限制,后定义的属性由于没有在初始化时绑定监听,所以Vue无法捕捉后定义属性的行为,为了弥补这种场景无法触发视图更新的问题,Vue在实例上提供了一个$set函数,用来辅助更新视图,其操作方式 如下:
vm.$set(要更新的对象,要设置的key,要设置的值)
2.使用$forceUpdate()强制渲染
除了$set之外,Vue还提供了一个API叫$forceUpdate 来实现视图的更新,它同样拴载在Vue的实例对象上,不同于forceUpdate不需要指定要更新的属性,他会在执行的时候强制Vue实例重新执行一次渲染,这样视图层所有的内容都会重新执行一次更新,在这之前如果有后定义的属性进行更改同样也会体现在视图上,这种方式只适用于特殊场景否则会让渲染性能开销增大。
2、Object.defineProperties
<script>
var obj = { name:123 }
// 影子变量 给set函数用的
var objTemp = { name:123 }
// 对象 设置被监控的属性 配置项
Object.defineProperty(obj,'name',{
set(value){
console.log("set函数被触发")
console.log(value)
// set函数中的this指向obj本身
// 如果直接使用this.name或者obj.name赋值会触发set无限死循环直到栈溢出
// obj.name = value
objTemp.name = value // 解决办法就是搞多一个影子变量 借壳
},
get(value){
console.log("get函数被触发")
console.log(value)
// return value
// objTemp
return objTemp.name
}
})
</script>
2.1、模拟vue2.x的data
<p>
姓名:<input type="text" name="name" />
年龄:<input type="text" name="age" />
性别:<input type="text" name="sex">
</p>
<div id="text"></div>
<script>
var onj = { name:"小明", age:18 }
// 影子对象
// var onjTemp = { name:"小明", age:18 }
var onjTemp = {} // 影子对象可以为空对象
Object.keys(onj).forEach(item=>{
// CSS [attribute=value] 选择器
var ipt = document.querySelector(`input[name=${item}]`)
// 为onj对象中的属性设置getter和setter
Object.defineProperty(onj,item,{
set(value){
console.log(value) // sex没有被监听 所以无法被响应式 除非初始化时加上
onjTemp[item] = value
ipt.value = value // 双向绑定 为了让数据改变从而修改输入框的数据
text.innerText = JSON.stringify(onjTemp)
},
get(value){
return onjTemp[item] // 从影子对象总取值
}
})
ipt.oninput = function(e){
onj[item] = e.target.value
}
})
/*
以上案例为了显示VUE在初始化时会递归我们的onj对象,如果对象中有初始化的属性时,
就能确保该对象被监听
*/
</script>
vue官网中也有说明: