循环渲染多个下拉框时双向数据绑定(v-model)失效的解决办法(坑死啊啊啊)

772 阅读2分钟

「这是我参与2022首次更文挑战的第18天,活动详情查看:2022首次更文挑战」。

一、需求描述

基于vue+element ui实现复杂表格这篇文章的代码,现在有一个需求是在表格的每一个表头新增一个下拉框,到时候表格的数据可根据下拉框的选项进行数据切换。

二、实现方式

第一步、在第一层 “el-table-column” 标签中嵌套如下代码:

注意:slot="header" 和 slot-scope="scope" 必须写,否则不生效。

<template slot="header" slot-scope="scope">
      <span style="color: black;font-size:18">
        {{ value1['label'] }}
      </span>
      <el-select
         v-model="headerSelected"
         style="width:50%;"
      >
         <el-option
            v-for="item in headerSelect"
            :key="item.value"
            :label="item.label"
            :value="item.value"
         />
      </el-select>
</template>

第二步、在 js 中定义下拉框选项 “headerSelect” 及选中值所需变量 “headerSelected”:

headerSelected 默认值为 "one"

headerSelect: [
    { label: '选项1', value: 'one' },
    { label: '选项2', value: 'two' }
],
headerSelected: 'one'

第三步、页面渲染及效果如下所示:

通过该演示可知,表格头部下拉框成功实现,但是仍然存在一个问题,那就是当我切换某一个下拉框的值的时候,其余下拉框的值也跟着改变了。原因是因为我们循环渲染出来的下拉框 v-model 了同一个变量 “headerSelected”。知道问题所在,那么解决办法就有了,我们让下拉框 v-model 不同的变量,具体实现如下:

第四步、第三步中 bug 解决办法

1、将变量 “headerSelected” 定义成一个对象;

headerSelected: {}

2、将 key 作为变量 “headerSelected” 中每一项的键,v-model 对应键即可。

<el-select
  v-model="headerSelected[key1]"
  style="width:50%;"
>
	<el-option
	  v-for="item in headerSelect"
	  :key="item.value"
	  :label="item.label"
	  :value="item.value"
	/>
</el-select>

3、效果如下:

由图可知,每个下拉框之间互不影响了,但是默认值怎么设置呢,这里在设置默认值是又有一个大坑。

第五步、设置下拉框默认值

由于后台传给我们的数据是动态的,我们并不确定表头是多少列,所以这里我们不能直接把变量 “headerSelected” 设置死,也只能是动态的,所以在页面初始化的时候,我们就需要遍历 tableData,依次往变量 “headerSelected” 中塞值。具体代码如下:

created() {
    this.tableData = tableJsonData
    for (var index in this.tableData['header_labels']) {
      this.headerSelected[index] = 'one'
    }
    console.log(this.headerSelected)
},

效果如下:

由上图可知,下拉框默认值设置成功,下面进行演示如下:

由上面的演示可知,不管怎么选下拉框的值,都不生效(这是最大的一个bug,研究了一天才解决,期间一度崩溃,只怪我太菜,TMD)。原因是 v-model 绑定的变量 “headerSelected” 在初始化设置默认值时不能直接被使用,要做一个中转(具体什么鬼,我也不知道)。

第六步、第五步中 bug 的修改如下:

created() {
    this.tableData = tableJsonData
    var copy_headerSelected = {}//中转变量
    for (var index in this.tableData['header_labels']) {
      copy_headerSelected[index] = 'one'
    }
    this.headerSelected = copy_headerSelected
},

效果如下: