解决数据更新, Vue slot 内容视图不更新

1,751 阅读1分钟

问题

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 就可以了。