携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第25天,点击查看活动详情
之前的那个,搜索框,搜索条件过多时,“折叠”/“展开” 按钮不会主动加载,而且当我切换表的时候,所有表共用一组 “折叠”/“展开”,也就是说如果表1,搜索条件很多,应该展示 “折叠” 按钮,页面不会主动加载,我还要鼠标点击一下页面,才会出现;而这时,如果我切换到查询条件较少的表2,按理说不用折叠,但 “折叠” 按钮还是在,必须鼠标点一下该按钮,才会触发事件,使按钮消失;这时如果再切换回表1,仍然是没有 “折叠” 按钮的......具体的问题描述可以看这里。不过今天,将这个 “折叠” 按钮问题解决了,请教了前辈,大佬帮忙解决的🙂 过程中学到一点东西,复盘一下。
问题的解决
其实在这篇文章里,我分析的也差不多,所有表共用一个 searchBar,是因为这些表都是在一个页面内,我参考的页面代码,他们都是在不同的页面中,有不同的 searchBar,所以不会有这个问题,所以写法得变一变。
看问题过程中,大佬提到,问题关键就是,我在使用 searchBar 组件时,我的值在父组件中是改变了的,但子组件 searchBar 并不知道这些值已经变了,所以也就没有区分开来,所有表都用的同一个。
解决方法就是监控到我放在 searchBar 中的查询条件,如果有发生改变,及时反馈给 searchBar。这里监控,就用到了 $set()。
$set() 方法
场景
当生成 Vue 实例后,再次给数据赋值时,有时候并不会自动更新到视图上面,即,如果在实例创建后添加新的属性到实例上,不会触发视图更新。
案例
<template>
<div class="home">
<div>{{student}}</div>
<div v-for="(item,index) in items" :key="index">{{item}}</div>
<button @click="btn()">修改</button>
</div>
</template>
<script>
export default {
name: 'Home',
data(){
return{
student:{
name:'张三',
},
items:[1, 2, 3],
}
},
methods:{
btn(){
this.student.age = 18;
this.items[1] = 'two';
console.log(this.student,this.items);
}
}
}
</script>
点击“修改”按钮后,页面上:
点击“修改”按钮后,控制台中:
可以看出,元素的内容其实是改变了的,但页面中视图并没有及时更新。
出现这种现象的原因:
受 ES5 的限制,Vue.js 不能检测到对象属性的添加或删除。因为 Vuew.js 在初始化实例时将属性转为 getter/setter,所以属性必须在 data 对象上才能让 Vue.js 转换它,才能使它是响应的。
其他一些类似操作&&使用set()解决
- 利用索引直接设置一个元素时,如:vm.items[indexOfItem] = newValue;
- 修改数组长度时,如:vm.items.length = newLength;
- 使用 this.arr[0] 去更新数组 array 的元素,视图不会刷新;
- 使用 Vue.set(this.arr, 0, !this.arr[0]) 去更新数组 array 的内容,视图会刷新;
- 使用 this.arr[0] = !this.arr[0] 和 this.obj.a = !this.obj.a 同时更新,视图会刷新;
总结:
如果方法里面单纯的更新数组 array 的话,要使用 Vue.set(); 如果方法里面同时又数组和对象的更新,直接操作 data 即可;
使用 Vue.set() && $set() 改写上述案例
使用 Vue.set()
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 实例的根数据对象。
案例:
<template>
<div class="home">
<div>{{student}}</div>
<div v-for="(item,index) in items" :key="index">{{item}}</div>
<button @click="btn()">修改</button>
</div>
</template>
<script>
import Vue from 'vue'
export default {
data(){
return{
student:{
name:'张三',
},
items:[1, 2, 3],
}
},
methods:{
btn(){
Vue.set(this.student, 'age', 18);
Vue.set(this.items, 1, 'two');
console.log(this.student,this.items);
}
}
}
</script>
点击“修改”按钮后,页面上:
点击“修改”按钮后,控制台中:
使用 $set()
$set() 语法
vm.$set( target, propertyName/index, value )
参数:
{Object | Array} target
{string | number} propertyName/index
{any} value
返回值:设置的值。
用法:
这是全局 Vue.set 的别名。
参考:Vue.set
案例
<template>
<div class="home">
<div>{{student}}</div>
<div v-for="(item,index) in items" :key="index">
<span>年龄:{{item.age}}</span>
<span>地点:{{item.address}}</span>
</div>
<button @click="btn()">修改</button>
</div>
</template>
<script>
import Vue from 'vue'
export default {
data(){
return{
student:{
name:'张三',
},
items:[
{
age:12,
address:北京,
},
{
age:13,
address:上海,
},
{
age:14,
address:广州,
}
],
}
},
methods:{
btn(){
this.$set(this.student, 'age', 18);
this.$set(this.items, 1, {age:22, address:'深圳'});
console.log(this.student,this.items);
}
}
}
</script>
点击“修改”按钮后,页面上:
点击“修改”按钮后,控制台中:
总之,感觉今天因为一个 $set() 不懂,大佬在帮忙看问题时,我都是一脸懵,本来还想着趁着大佬指导,学习一下他解决问题的思路,但发现思维完全跟不上,Vue!!!我恨......
希望本文能够帮到你,如有错误,望指正!
我向你敬礼啊,Salute!