最近遇到一个需求,前端要求动态生成checkbox并实时将选中的值展示出来。组件使用了antd-vue的checkbox。其实上这个需求是很简单的,但是测试提的一个优化项导致了悲剧的开始!
设计稿大致就是这个样子,很简单:
使用过antd-vue组件的朋友们可能很熟悉checkbox-group组件,这里我将简单的代码贴出来。我是拿了项目的配置数据动态生成checkbox。没毛病,能选,能展示!完美~~~
<template>
<div class="test-container">
<a-checkbox-group v-model="checkValue" @change="onChange">
<a-checkbox v-for="item in plainOptions" :key="item" :value="item">{{item}}</a-checkbox>
</a-checkbox-group>
<div>选择:{{checkValue}}</div>
</div>
</template>
<script>
export default {
data(){
return{
plainOptions : ['A', 'B', 'C', 'D'],
checkValue: []
}
},
methods:{
onChange(e){
console.log(e) // ["D", "B", "C", __ob__: Observer]
}
}
}
</script>
<style lang='less' scoped>
.test-container{
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
</style>
是不是很丑,选择的答案不能展示数组啊!猛男审美绝对不能允许!怎么办?vue里面有filter呀!于是乎有如下修改,是不是好看了很多?
//HTML添加:
<div>选择:{{checkValue | checkValueFilter}}</div>
//js里面添加
checkValueFilter: (value)=>{
if(!value.length) return '-'
return value.join(',')
}
当一切都准备结束的时候,测试小姐姐提优化啦!能不能展示的时候按照字母排序提交?想都没想就答应了Array不是有sort()嘛,两分钟搞定!!!
//HTML添加:
//js里面添加
filters:{
checkValueFilter: (value)=>{
if(!value.length) return '-'
return value.sort().join(',')
}
}
高高兴兴提交代码去吃饭啦!!!回来继续测试,崩溃,再次点击checkbox页面无任何反应。直接崩溃,也无报错信息也无任何资源请求。我与测试四目相对,这绝对不是我的bug,先甩锅,服务器部署是不是出问题了,我这加的代码人畜无害呀!!!重启服务器,重新部署再次点击,仍然崩溃。猛男落泪。哪出问题了?一开始以为是checkbox的问题,改了无数次代码,没有任何问题。最终在多次尝试下终于排查到了新加的filters代码。
1.Array.sort()注意事项:
sort() 方法用原地算法对数组的元素进行排序,并返回数组。默认排序顺序是在将元素转换为字符串,然后比较它们的UTF-16代码单元值序列时构建的。也就是说sort()方法是改变原数组的。
2.vue的响应式原理:
vue对于数组的更新检测包含了一组观察数组的编译方法即push(),pop(),shift(),unshift(),splice(),sort(),reverse() 。在filter中调用以上的方法就会导致无限的更新循环。很明显造成页面卡死的原因就是忽视了这一茬。
3.解决办法:
1.在使用filters时不直接操作数据源避免触发更新机制:
checkValueFilter: (value)=>{
if(!value.length) return '-'
const array = [...value]
return array .sort().join(',')
}
2.也可使用computed计算属性(计算属性和上面的思想是一样的):
computed:{
answerFilter(){
if(!this.checkValue) return '-'
const array = [...this.checkValue] // 为什么要浅拷贝一份?computed是不允许直接改变data里面的值的,具体参见官方教程
return array.sort().join(',')
}
},
写在最后
bug虽然找到了但是仔细想了想出现这个问题的原因终究还是没有仔细阅读文档,再加上平时使用filters比较少,有些坑以前可能没踩到。最后还仔细阅读了一下antd的文档
<template>
<div>
<a-checkbox-group
v-model="value"
name="checkboxgroup"
:options="plainOptions"
@change="onChange"
/>
</div>
</template>
<script>
const plainOptions = ['Apple', 'Pear', 'Orange'];
export default {
data() {
return {
plainOptions,
value: [],
};
},
methods: {
onChange(checkedValues) {
console.log('checked = ', checkedValues);
console.log('value = ', this.value);
},
},
};
</script>
这里也是根据配置自动生成checkbox呀,而他用的是options的方式。那我也来换一下,去掉filters里面的sort()操作,代码跑起来,感觉损失了半个亿。
<a-checkbox-group :options="plainOptions" v-model="checkValue" @change="onChange">
无论何种点击顺序,展示都是按照A-Z展示的。猛男落泪,为什么犯贱自己去循环,为什么要去sort(),排查这些问题可花了好长时间啊,划划水不香吗???还有为啥页面不打印错误信息呢?因为我这边的代码比较特殊有些操作需要部署到线上才能正常调试,在遇到这块问题的时候,点击选项页面直接卡死根本不给报错的机会。。。后来在本地调试确实看到了报错信息。还是大意了,大意了!
这次坑踩得很结实,以后希望不要再犯!!!