问题
Vue 很多场景,slot 中组件会用到父组件的数据,父组件数据更新,并不能触发 slot 内的子组件更新
例如:el-table 中通过 showForm 字段控制是否显示输入框。
<el-table
border
:data="data"
>
<el-table-column
v-for="(item, index) in columns"
:key="item.name"
:prop="item.name"
:label="item.label"
min-width="140"
:show-overflow-tooltip="true"
>
<template #header>
<el-input
v-if="item.showForm"
v-model="item.alias"
/>
<span v-else>{{ item.alias }}</span>
</template>
</el-table-column>
</el-table>
methods: {
update () {
// 并不会触发视图更新
columns[0].showForm = true
}
}
类似的场景还有很多,例如 el-tabs 的 slot 中有用到父级数据。
解决思路
未深入了解,初步定位是因为父级组件数据有更新,依赖也被收集,更新时 Diff 时出了问题,由于对比 el-table-column 时,发现所有属性并未变化,所以就不会重新渲染 el-table-column 中的内容。
由此结论,只要让 el-table-column 属性有变化,Diff 时就会重新渲染。最简单的方法就是改变 key 值。
解决方案
<el-table-column
v-for="(item, index) in columns"
:key="item.uuid"
:prop="item.name"
:label="item.label"
min-width="140"
:show-overflow-tooltip="true"
>
</el-table-column>
created () {
this.columns.forEach(column => {
column.showForm = false
column.uuid = column.name
})
},
methods: {
update () {
columns[0].showForm = true
// update uuid ,从而触发 key 改变重新渲染视图
columns[0].uuid = columns[0].name + columns[0].showForm
}
}
上面我们使用 uuid 作为 el-table-column 的 key,需要更新哪个就去改变 uuid 就可以了。