elementUI下拉单选框出现双重选中bug解决方案

问题重现

这个bug是我在工作的时候处理过的一个问题,今天特地将bug问题剥离出来记录一下以作备忘。话不多说,直接上图:


elementUI下拉单选框出现双重选中bug解决方案_第1张图片
bug示例

问题排查

当时我看到之后第一反应以为下拉框启用了多选,去检查了一下后发现

el-select(v-model="options.selected.value")
    el-option(v-for="item, index in options.list" 
              :key="index" 
              :label='item.name' 
              :value='item.value')

没开multiple啊


elementUI下拉单选框出现双重选中bug解决方案_第2张图片

然后去检查了下逻辑代码,发现这个下拉选单的内容是在初始化时动态加载的,获取到内容后先赋值给下拉选单的列表,然后取列表第一个内容当作默认选中值。

加载代码段

...
mounted() {
    this.getSelectList().then(resp => {
        this.options.list = resp.data
        this.options.selected = resp.data[0]
    })
}
...

data代码段

data: () => ({
    options: {
        selected: {},
        list: []
    }
}),

这里我们用promise模拟一个数据请求

getSelectList() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            const resp = {
                data: [
                    { value: 1, name: '选项1' },
                    { value: 2, name: '选项2' },
                    { value: 3, name: '选项3' },
                    { value: 4, name: '选项4' }
                ]
            }
            resolve(resp)
        }, 1000)
    })
}

检查了一下发现好像并没有什么不对,随后一起检查这个bug的同事把请求的内容直接放在本地data里测试了一下,bug消失了。那问题肯定就出现在在加载列表内容的那两行代码里。其实现在已经很明显了,我们直接祭出杀器Vue Devtools检查一下运行时的状态再确认一下。

elementUI下拉单选框出现双重选中bug解决方案_第3张图片
Vue Devtools

当我们 点击选项3的时候,发现 不止是selected的值被改变了, list[0]值也被修改了!水落石出,这是一个由数据浅拷贝引发的bug。
由于selected在赋值时只是进行了浅拷贝,所以selected其实是list[0]的一个引用,所以list[0]的值也会被el-select修改成被选中的值,页面在渲染时发现list[0]的key和被选中的key相同,自然就显示成选中状态了。

问题解决

只需要把浅拷贝换成深拷贝即可,这里我们直接用JSON.parse()JSON.stringify()深拷贝一下,这样selected和list[0]就不会相互干扰了。

mounted() {
    this.getSelectList().then(resp => {
        this.options.list = resp.data
        this.options.selected = JSON.parse(JSON.stringify(resp.data[0]))
    })
}

问题总结

  • 在发现出现数据污染的情况,特别是数据里包含数组或对象(这个基本避免不了),或者从数组里取值赋给某个值的时候,要优先考虑深浅拷贝的问题。
  • Vue Devtools真好用。

你可能感兴趣的:(elementUI下拉单选框出现双重选中bug解决方案)