Vue v-data-table封装组件同列值名覆盖问题求助
解决v-data-table封装组件中同value列格式化值覆盖问题
问题原因
- 封装组件的
remappedItems计算属性中,直接修改了父组件传入的props.headers内的header对象属性(header.value = key),污染了原始表头数据。 - 当两个列初始
value相同时,模板渲染阶段会生成两个同名插槽(如item.refuseCodeReason),后定义的插槽会覆盖前一个,导致第一列显示第二列的格式化内容。
解决方案
1. 避免修改原始表头对象
在remappedItems计算属性中,创建表头副本进行处理,禁止修改父组件传入的原始表头数据:
const remappedItems = computed(() => { function getItemValue( value: unknown, formatter?: (value: unknown) => unknown ) { if (formatter) { return formatter(value) } return value === null || value === undefined || value === '' ? '—' : value } // 创建表头副本,避免污染原始props.headers const processedHeaders = props.headers?.map(header => ({ ...header })) || [] return props.items?.map((item) => { const newItem: Record<string, unknown> = { ...item } if ('links' in newItem) { delete newItem.links } processedHeaders.forEach((header) => { const key = header.key || header.value newItem[key] = getItemValue(get(item, header.value), header.formatter) // 移除修改原始header.value的代码 }) return newItem }) })
2. 调整模板插槽与数据读取逻辑
修改模板中的插槽命名规则,确保每个列使用唯一的插槽名,同时统一数据读取的字段标识:
<template v-for="header in headers" #[`item.${header.key || header.value}`]="{ item }"> <div :key="header.key || header.value" :style="{ width: header.width }"> <!-- 自定义插槽渲染 --> <template v-if="header.type === 'slot'"> <slot :name="header.key || header.value" :row="item" /> </template> <!-- 常规渲染逻辑 --> <template v-else> <div v-if="header.type === 'link'"> <nuxt-link v-if="header.customProps" v-bind="header.customProps(item)" > {{ item[header.key || header.value] }} </nuxt-link> </div> <div v-else-if="header.type === 'date'"> {{ formatDateTime(item[header.key || header.value], { format: header.dateFormat, }) || item[header.key || header.value] }} </div> <div v-else-if="header.type === 'checkbox'"> <v-checkbox :input-value="getCheckboxValue(item[header.key || header.value])" readonly v-bind="header.customProps" /> </div> <div v-else-if="header.type === 'button'"> <ConsBtn v-bind="header.customProps" @click="header.clickEvent ? header.clickEvent(item) : null" > {{ item[header.key || header.value] }} </ConsBtn> </div> <!-- eslint-disable-next-line vue/no-v-html --> <div v-else-if="header.isHtml" v-html="item[header.key || header.value]" /> <div v-else> {{ item[header.key || header.value] }} </div> </template> </div> </template>
核心修改点:
- 插槽名从
item.${header.value}改为item.${header.key || header.value},确保带key的列使用唯一插槽名 - 所有读取数据的位置统一使用
header.key || header.value,匹配remappedItems中赋值的字段
3. 验证排序逻辑(可选)
若排序依赖表头字段,只需确保父组件传入的sort参数与header.key || header.value一致即可,现有sortOptions逻辑无需修改。
效果说明
修改后,两个列会分别使用独立的插槽(item.refuseCodeReason和item.refuseCodeReasonFormatted),不会出现内容覆盖问题:
- 第一列显示原始
refuseCodeReason值 - 第二列显示格式化后的值
内容的提问来源于stack exchange,提问作者Alexander Kim
相关产品推荐
相关产品推荐

