解决vue3中from表单嵌套el-table时填充el-input,v-model不唯一问题
作者:LinHan
今天,在项目中遇到这样一个效果,具体如下
布局
相信这个布局应该不难,无非就是在表单中嵌套表格而已,代码结构我也发放在下面
那么老板要什么效果呢?
其实就是,当你点击批量填充的时候,将从form中收集到的服务费率和推广结束时间填充到组件table对应位置
问题分析
底部table的数据是请求得到的,或者是组件传值得到的,我们具体也不知道有多少条。
那么对应的输入框和时间选择器显然不可以绑定同一个v-model
否则,修改其中一个输入框的v-model,就会影响其他的输入框
提交表单时,table里面的输入框和时间选择器依旧可以正常输入和选择
也就是说我既可以批量修改,也可以单独修改,
尝试
第一次尝试的时候,我在table底下的输入框和时间选择器的v-model上分别在form表单的prop声明上同时声明了各自的v-model,并且获取scope.row.id用于绑定每一行唯一的v-model,代码如下:
<el-table-column prop="product_number" label="服务费率" width="200"> <template #default="scope"> <div> <el-input size="small" v-model="tableServiceRate[scope.row.id]" ></el-input> </div> </template> </el-table-column>
绑定的v-model
interface IForm { serviceRate: String | null; time: Date; activeLink: string | null; phone: number; tableServiceRate: string[]; tableTime: Date[]; } const productForm = ref<IForm>({ serviceRate: '', time: '', activeLink: '', phone: null, tableServiceRate:[]//服务费率 tableTime:[]//table时间选择器 });
之后给批量填充绑定点击事件
因为,批量填充要求服务费率或者推广结束时间至少填写一个!
所以,我们先去做一个简单的判断,并且加上对应的消息提示
// 批量填充 const handleBatchFill = () => { if (productForm.serviceRate === '' && productForm.time === '') { ElMessage({ type: 'warning', message: '服务费率或者推广结束时间至少填写一个!', }); return; } };
接下来才是正题,
因为之前我们给table的输入框绑定的是带有当前行数据id标识的v-model
这样确保了每一行循环出来的输入框的v-model的唯一性
所以这里,我们在点击事件里,去循环table的数据,找到id,然后去table外部form表单项的输入框的值,赋值给productForm.tableServiceRate这个数组里key为id值的项,
ProductSaleListData.forEach((item) => { productForm.tableServiceRate[item.id] = productForm.serviceRate; productForm.tableTime[item.id] = productForm.time; });
这时候出现一个报错信息,它提示声明的productForm.tableServiceRate数组里不能设置未定义的key id
因为这时候遍历出来的id值是数字,例如:8
后面修改为字符串之后还是不行,
这时,我想到,使用re'reactive去声明,修改之后,果然,不报错了,
我刷新之后,发现,咦!为什么打印修改之后的数组,里面需要的值正常填进去了,但是,视图没有更新,一直处于空状态,
后面了解到,在vue3中reactive有时会失去响应,
基于此,我又将代码修改如下:
const productFormNew = toRef(productForm)
后面再循环赋值时,使用toRef后的响应式对象
但是,效果依旧没有实现,还是死驴不动弹!!!
转换思路
我们可以利用nextTick立即获取组件更新后的值
全局 API:常规 | Vue.js (vuejs.org)
官方解释:当你在 Vue 中更改响应式状态时,最终的 DOM 更新并不是同步生效的,而是由 Vue 将它们缓存在一个队列中,直到下一个“tick”才一起执行。这样是为了确保每个组件无论发生多少状态改变,都仅执行一次更新。
nextTick() 可以在状态改变后立即使用,以等待 DOM 更新完成。你可以传递一个回调函数作为参数,或者 await 返回的 Promise。
ProductSaleListData.forEach((item) => { console.log(item.id); nextTick(() => { productForm.tableServiceRate[item.id] = productForm.serviceRate; productForm.tableTime[item.id] = productForm.time; }); console.log(productForm.tableServiceRate, '-d-d-d-d--'); });
后面发现这里不应该用nextTick
晕死~~~~
继续转换思路
我们可以使用 watchEffect监听值的更新,每次点击都将form表单的输入框的值赋给table
ProductSaleListData.forEach((item) => { console.log(item.id); watchEffect(() => { productForm.tableServiceRate[item.id] = productForm.serviceRate; productForm.tableTime[item.id] = productForm.time; }); console.log(productForm.tableServiceRate, '-d-d-d-d--'); });
惊奇的发现效果可以实现
我以为到此就可以结束了
但是,bug来了
实际效果是,当我点击批量填充后,table没有变化,但是,当我继续点击tablel里面的输入框时,它才会将form的值更新到table项上
出错原因:因为我将weatchEffect写在了点击事件里面 每次点击之后,它才会开启监听数据并赋值
那我将weatchEffect单独提出来,在监听响应式数据的变化,
呃,一切回到解放前,底部table又没有了变化
继续转换思路
经过,数次打磨,
这次
<el-table-column prop="product_number" label="服务费率" width="200"> <template #default="scope"> <div> <el-input size="small" v-model="tableServiceRate[scope.$index]" :value="productForm.serviceRate"></el-input> </div> </template> </el-table-column> <el-table-column prop="wait_delivery_num" label="推广结束时间" width="264"> <template #default="scope"> <el-date-picker size="small" v-model="tableTime[scope.$index]" :value="productForm.time" style="width: 220px" type="date" /> </template> </el-table-column>
v-model="tableTime[scope.$index]"
:使用Vue.js的双向数据绑定,将日期选择器的值和tableTime数组中的指定索引位置进行绑定。即当日期选择器的值发生变化时,tableTime数组中对应位置的值也会改变。:value="productForm.time"
:将productForm对象中的time属性的值作为日期选择器的默认值。然后,去把table输入框绑定的v-modle的值从form里面提出来,单独声明ref的响应式数据
利用内部value的修改,去强制修改v-model的值
并且不再利用当前行数据的id去做唯一性处理,而是利用当前行的索引,
并且,在点击事件里面修改如下:
const tableServiceRate = ref<string[]>([]); // 设置表格的input const tableTime = ref<Date[]>([]); // 设置表格的time const handleBatchFill = () => { if (productForm.serviceRate === '' && productForm.time === '') { ElMessage({ type: 'warning', message: '服务费率或者推广结束时间至少填写一个!', }); return; } else { if (productForm.serviceRate) { tableServiceRate.value = Array(ProductSaleListData.length).fill(productForm.serviceRate); } if (productForm.time) { tableTime.value = Array(ProductSaleListData.length).fill(productForm.time); } } console.log('批量填充', tableServiceRate.value); };
将一个具有相同元素的数组赋值给名为tableServiceRate
的变量。该数组的长度由ProductSaleListData
数组的长度决定,并且每个元素的值都是productForm.serviceRate
。
换句话说,如果ProductSaleListData
数组长度为n,那么tableServiceRate
数组将包含n个元素,每个元素的值都是productForm.serviceRate
。这样可以简化对数组元素的赋值过程,使每个元素都具有相同的数值。
这样,就完成了数据批量填充。
到此这篇关于解决vue3中from表单嵌套el-table时填充el-input,v-model不唯一问题的文章就介绍到这了,更多相关vue3 from填充el-input,v-model不唯一内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
您可能感兴趣的文章:
- vue3 实现关于 el-table 表格组件的封装及调用方法
- vue3+elementplus基于el-table-v2封装公用table组件详细代码
- vue3+ts+vite使用el-table表格渲染记录重复情况
- Vue3中el-table表格数据不显示的原因和解决方法
- vue3插槽:el-table表头插入tooltip及更换表格背景色方式
- vue3使用element-plus中el-table组件报错关键字'emitsOptions'与'insertBefore'分析
- vue3 el-table结合seamless-scroll实现表格数据滚动的思路详解
- vue3 el-table 如何通过深度选择器::v-deep修改组件内部样式(默认样式)