Vue中如何基于数组动态增删slot字段?删除slot总移除最后一项怎么解决
问题原因
v-for绑定的:key使用了数组下标index。当你删除某一行后,剩余数组的下标会重新排列,Vue的Diff算法会默认复用下标对应的DOM节点,导致静态slot内容出现渲染错位。你观察到输入框能正常删除,是因为输入框绑定了row.value和每行数据响应式关联,Vue能正确跟踪值的变化,而静态插槽没有和行数据做绑定,所以复用后出现错位。- 你使用了固定名称的具名插槽
name="fields",同一个组件内同名的具名插槽只会被注入一次父级传入的内容,循环中的所有插槽本质上复用的是同一份静态内容,自然无法和对应的行做绑定删除。
解决方案
第一步:给每行数据加唯一标识,替换掉index作为key
修改addRow方法,新增行时生成唯一ID作为每行的固定标识,避免用下标做key:
removeRow(index){ this.rows.splice(index, 1); }, addRow(){ this.rows.push({ id: Date.now() + Math.random(), // 只要保证唯一即可,也可以自己维护自增ID value: 'test' }) }
修改v-for的key绑定:
<div v-for="(row, index) in rows" :key="row.id"> <div class="d-flex justify-content-between "> <slot name="fields" :row="row" :index="index"> </slot> <input v-model="row.value" /> <button @click="removeRow(index)" type="button" class="btn btn-primary waves-effect waves-float waves-light height-10-per " > Remove <i class="fa fa-times-circle"></i> </button> </div> </div>
第二步:父组件改用作用域插槽语法传入内容
作用域插槽可以给循环的每一行单独传递插槽内容,父组件调用时写法如下(不需要用到行数据也可以不接收参数,只要用作用域插槽的写法就能保证每行的插槽独立):
<!-- 父组件使用示例 --> <your-component :rows="rows"> <template v-slot:fields="{ row, index }"> <!-- 这里放你原来要传入插槽的HTML内容 --> </template> </your-component>
简化方案(如果插槽内容固定不需要父级动态传入)
如果插槽里的内容是固定的,完全不需要父级传递,直接把插槽内容写到组件内部的v-for循环里即可,不需要用插槽,自然不会有渲染错位问题。
内容的提问来源于stack exchange,提问作者Madmunster
相关产品推荐
相关产品推荐

