目录
发现问题思考问题解决问题1. 问题原因分析,及解决思路 完整代码title: Vue.js+ElementUI多选表格下拉框有默认值后不及时更新
date: -8-1 14:40:00
tags:
学习Vue.jsElementUI前端记录问题
categories:bug
Vue.js+ElementUI项目中多选表格下拉框有默认值后不及时更新
发现问题
最近几天项目中有个需求,Vue+elementUI实现的一个多选表格,然后表格中有一列需要自己加一个下拉框,且下拉框有一个默认选中的值,实现后,发现下拉框重新选择值后居然没有及时更新,需要点中表格前面的checkbox勾选框后才更新,让我百思不得其解。
思考问题
一开始我认为是因为我绑定了默认值,导致不能及时更新,但是默认值又是需要实现的一个功能,所以不得不写,后面我以为是我绑定的值不对导致没有及时更新,我将下拉框选项数组换成了如下格式的一个对象数组,仍然不能及时更新!!
[{label: '选项1',value: 1},{label: '选项2',value: 2},{label: '选项3',value: 3},{label: '选项4',value: 4},{label: '选项5',value: 5},]
我就想可能是因为vue视图没有及时相应,所以我添加了如下代码想让table表格的内容强制更新,但是遗憾的是仍然没能及时更新。
BindChange(rowdata){console.log(rowdata);// 获取当前行的数据对象// const rowData = this.tableData[rowIndex];// 将新选择的值更新到表格数据中// this.tableData[rowIndex].value = rowData.value;rowdata.value = rowdata.value;console.log(this.tableData);this.$forceUpdate();//强制更新,不起作用!Vue官网不推荐使用}
解决问题
后来正在我头疼之际,找到了一个看似可行的方法,然后我试了一下果然就起作用啦!
1. 问题原因分析,及解决思路
(1)
v-model
绑定与this.$set
触发视图更新
在Vue中,当使用v-model
绑定一个属性时,Vue会根据绑定的值自动处理更新。但在这个问题的情况下,v-model
绑定的是scoped.row.value
,而不是rowData
中的value
属性。
所以,更新rowData
中的value
并不会直接触发视图的更新。
为了解决这个问题,我们需要手动更新scoped.row.value
。这可以通过给scoped.row
对象重新赋值的方式来实现,强制触发Vue的响应式系统。
我们在BindChange
方法中重新给scoped.row
赋值,使用this.$set
来触发视图的更新。这样应该能解决下拉框选择值后表格数据没有及时更新的问题。
(2)详细方法
BindChange(rowData, rowIndex) {// 通过方法参数直接获取当前行的数据对象和索引-------07-30// 直接更新rowData中的value属性console.log('row数据',rowData);console.log('rowIndex',rowIndex);this.tableData[rowIndex].value = rowData.value;// 重新赋值scoped.row触发视图更新this.$set(this.tableData, rowIndex, Object.assign({}, rowData));console.log('更新后的tableData',this.tableData);}
(3)说明与总结
当使用Vue进行数据绑定时,通常情况下,Vue能够自动追踪数据的变化并更新视图,这被称为"响应式系统"。但在某些情况下,直接赋值一个新值给对象属性可能无法触发响应式更新,特别是对于在Vue实例创建时不存在的属性。
this.$set
方法是Vue提供的一种手动触发响应式更新的方式,用于更新对象或数组中的某个元素或属性。
语法:
this.$set(target, propertyName/index, value);
参数说明:
target
: 要更新的目标对象或数组。
propertyName/index
: 要更新的属性名或数组索引。
value
: 要设置的新值。
使用this.$set
方法,Vue会监听新设置的值并将其添加到响应式系统中,从而确保更新可以正确地触发视图更新。
在提供的代码中,this.$set(this.tableData, rowIndex, Object.assign({}, rowData))
用于更新this.tableData
数组中的第rowIndex
个元素。
让我们分解一下这个代码的含义:
Object.assign({}, rowData)
: 这里使用Object.assign
方法,通过浅拷贝的方式创建了一个新对象。这样做的目的是为了确保rowData
的变化不会影响到this.tableData
中的数据。因为直接赋值一个对象引用的话,两个变量会指向同一个内存地址,导致变化不会触发响应式更新。
this.$set(this.tableData, rowIndex, ...)
:这里使用this.$set
来更新this.tableData
数组中的第rowIndex
个元素。将新的对象赋值给这个索引处,从而触发响应式更新。
总结:
this.$set
方法的作用是确保更新的数据能够正确地触发Vue的响应式更新机制。它在更新对象或数组中的某个元素或属性时,可以让Vue监听新值并正确地进行视图更新。这在需要手动更新数据时,
特别是处理动态添加或删除属性的情况下非常有用。🎉🍭🍓🍬🎉
完整代码
//multipleTable.vue<template><div><el-tableref="multipleTable":data="tableData"tooltip-effect="dark"style="width: 100%"@selection-change="handleSelectionChange"><el-table-columntype="selection"width="55"></el-table-column><el-table-columnlabel="日期"width="120"><template v-slot="scope">{{ scope.row.date }}</template></el-table-column><el-table-columnprop="name"label="姓名"width="120"></el-table-column><el-table-columnprop="address"label="地址"show-overflow-tooltip></el-table-column><el-table-columnlabel="选项"><template v-slot="scoped"><el-select v-model="scoped.row.value" @change="BindChange(scoped.row, scoped.$index)"><el-optionv-for="item in scoped.row.choice":key="item.label":value="item.value":label="item.label"></el-option></el-select></template></el-table-column></el-table><div style="margin-top: 20px"><el-button @click="toggleSelection([tableData[1], tableData[2]])">切换第二、第三行的选中状态</el-button><el-button @click="toggleSelection()">取消选择</el-button></div></div></template><script>export default {name: 'MultipleTable',data() {return {tableData: [{date: '-05-03',name: '王小虎',address: '上海市普陀区金沙江路 1518 弄'}, {date: '-05-02',name: '王小虎',address: '上海市普陀区金沙江路 1518 弄'}, {date: '-05-04',name: '王小虎',address: '上海市普陀区金沙江路 1518 弄'}, {date: '-05-01',name: '王小虎',address: '上海市普陀区金沙江路 1518 弄'}, {date: '-05-08',name: '王小虎',address: '上海市普陀区金沙江路 1518 弄'}, {date: '-05-06',name: '王小虎',address: '上海市普陀区金沙江路 1518 弄'}, {date: '-05-07',name: '王小虎',address: '上海市普陀区金沙江路 1518 弄'}],multipleSelection: []}},mounted() {this.initTabledata();},methods: {BindChange(rowData, rowIndex) {// 通过方法参数直接获取当前行的数据对象和索引-------07-30// 直接更新rowData中的value属性console.log('row数据',rowData);console.log('rowIndex',rowIndex);this.tableData[rowIndex].value = rowData.value;// 重新赋值scoped.row触发视图更新this.$set(this.tableData, rowIndex, Object.assign({}, rowData));console.log('更新后的tableData',this.tableData);},// BindChange(rowdata){//// 获取当前行的索引//// console.log(select);//// const rowIndex = this.tableData.indexOf(select.$attrs.row);//// // 将新选择的值更新到表格数据中//// this.tableData[rowIndex].value = select;////console.log(rowdata);//// 获取当前行的数据对象//// const rowData = this.tableData[rowIndex];//// 将新选择的值更新到表格数据中//// this.tableData[rowIndex].value = rowData.value;//rowdata.value = rowdata.value;//console.log(this.tableData);//// this.$forceUpdate();// },initTabledata(){this.tableData.forEach(item => {item.value = 3;item.choice = [{label: '选项1',value: 1},{label: '选项2',value: 2},{label: '选项3',value: 3},{label: '选项4',value: 4},{label: '选项5',value: 5},]})},toggleSelection(rows) {if (rows) {rows.forEach(row => {this.$refs.multipleTable.toggleRowSelection(row);});} else {this.$refs.multipleTable.clearSelection();}},handleSelectionChange(val) {this.multipleSelection = val;console.log('当前选中的行的值',this.multipleSelection);}}}</script>