You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue v-data-table封装组件同列值名覆盖问题求助

解决v-data-table封装组件中同value列格式化值覆盖问题

问题原因

  1. 封装组件的remappedItems计算属性中,直接修改了父组件传入的props.headers内的header对象属性(header.value = key),污染了原始表头数据。
  2. 当两个列初始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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 07:17:03