ant design vue table表格组件,单元格内容超出列宽

501 阅读1分钟

背景

使用ant design vue table组件,通过#bodyCell="{ column, record }"定义表格行的内容模板。

               <a-table
                ref="tableRef"
                :class="[
                  lineParam.tableLineHeightClass,
                  !tableCfg?.data?.length && state.spinning && 'empty-table'
                ]"
                :row-selection="footShow ? rowSelection : null"
                :columns="tableCfg.columns"
                :data-source="tableCfg.data"
                :pagination="false"
                rowKey="key"
                :scroll="{ x: '100%', y: autoHeight }"
                @resizeColumn="handleResizeColumn"
              >
                <template #bodyCell="{ column, record }">
                  <template v-if="column.key === 'businessModuleList'">
                    <BusinessTag
                      v-if="record?.businessModuleNameList?.length"
                      :tags="record?.businessModuleNameList"
                      :show-count="2"
                      :column-width="columnWidth"
                    />
                    <div v-else>-</div>
                  </template>
                  <template v-if="column.key === 'name'">
                    .........
                  </template>
                <template #emptyText>
                  <img v-if="!state.spinning" src="@/assets/no-data.svg" />
                </template>
              </a-table>
column: [
    {
      title: '姓名',
      dataIndex: 'userDetail',
      key: 'userDetail',
      align: 'left',
      fixed: 'left',
      ellipsis: true,
      width: 350,
      resizable: true
    },
      {
      title: '负责业务模块',
      dataIndex: 'businessModuleList',
      key: 'businessModuleList',
      align: 'left',
      ellipsis: true,
      resizable: true,
      width: 250
    },
    .........
  ]

BusinessTag组件

<template>
  <div></div>
  <div class="business-tag" v-for="(item, index) in tagsList" :key="index">
    {{ item }}
  </div>
  <a-tooltip>
    <template #title>{{ tags?.join('、') }}</template>
    <div class="business-tag">
      {{ tagText }}
    </div>
  </a-tooltip>
</template>

<script lang="ts" setup>
import { computed } from 'vue'

const props = withDefaults(
  defineProps<{
    showCount?: number
    tags: string[] | null
  }>(),
  {
    //需要显示的tag数量,默认为3
    showCount: 3
  }
)

const tagText = computed(() => {
  if (!props.tags?.length) return
  const remainingTags = props.tags?.length - props.showCount
  return remainingTags > 0 ? `+${remainingTags}...` : ''
})

const tagsList = computed(() => props.tags?.slice(0, props.showCount))
</script>

<style lang="less" scoped>
.business-tag {
  display: inline-block;
  border-radius: 2px;
  width: fit-content;
  height: fit-content;
  color: black;
  background-color: #f5f5f5;
  padding: 0 5px;
  margin: 2px 3px;
}
</style>

其中key为businessModuleList的列,正常效果如下:

image.png

鼠标悬浮在”+n“的tag上时,展现所有内容

image.png

当其中的tag太长,如果按照现有展现方式,将出现隐藏,导致展现内容不完整且tooltip无法查看:

image.png

探索

尝试1

取消列配置中的溢出隐藏:

{
      title: '负责业务模块',
      dataIndex: 'businessModuleList',
      key: 'businessModuleList',
      align: 'left',
      ellipsis: true,
      //resizable: true,
      width: 250
    },

表格根据列宽,出现换行效果,由于产品不希望换行,所以此方案不行。

image.png

尝试2

取消溢出隐藏,并将businessTag组件html部分,外面再包了一层div,并添加display: inline-block

<template>
  <div style="display: inline-block">
    <div class="business-tag" v-for="(item, index) in tagsList" :key="index">
      {{ item }}
    </div>
    <a-tooltip>
      <template #title>{{ tags?.join('、') }}</template>
      <div class="business-tag">
        {{ tagText }}
      </div>
    </a-tooltip>
  </div>
</template>

image.png image.png

尝试3

重写组件,根据表格宽度决定展现几个标签,若表格宽度不够则至少展示一个标签和”+n“标签,若表格宽度足够,则展示showCount个标签和”+n“标签

思考一:如何获取内容宽度

添加ref,使用ref.value.clientWidth

<template>
  <div style="display: inline-block" ref="wrapper" v-if="tags?.length">
    <div class="business-tag" v-for="(item, index) in visibleTags" :key="index">
      {{ item }}
    </div>
    <a-tooltip>
      <template #title>{{ tags?.join('、') }}</template>
      <div class="business-tag">
        {{ truncatedTagText }}
      </div>
    </a-tooltip>
  </div>
</template>

<script lang="ts" setup>
import { computed, ref, onMounted } from 'vue'

const props = withDefaults(
  defineProps<{
    showCount?: number
    tags: string[]
    columnWidth: number
  }>(),
  {
    //需要显示的tag数量,默认为3
    showCount: 3
  }
)

const wrapper = ref(null)
const fixedShowCount = ref(props.showCount)

const visibleTags = computed(() => props.tags?.slice(0, fixedShowCount.value))

const truncatedTagText = computed(() => {
  if (!props.tags?.length) return ''
  const remainingTags = props.tags?.length - fixedShowCount.value
  return remainingTags > 0 ? `+${remainingTags}...` : ''
})

const checkAndAdjustShowCount = () => {
  if (wrapper.value) {
    const containerWidth = wrapper.value.clientWidth
    // 减去单元格左右padding
    if (containerWidth > props.columnWidth - 24) {
      fixedShowCount.value = 1
    } else {
      fixedShowCount.value = Math.min(props.showCount, props.tags?.length || 0)
    }
  }
}

onMounted(() => {
  if (wrapper.value) {
    checkAndAdjustShowCount()
  }
})
</script>

<style lang="less" scoped>
.business-tag {
  display: inline-block;
  border-radius: 2px;
  width: fit-content;
  height: fit-content;
  color: black;
  background-color: #f5f5f5;
  padding: 0 5px;
  margin: 2px 3px;
}
</style>

                <template v-if="column.key === 'businessModuleList'">
                    <BusinessTag
                      v-if="record?.businessModuleNameList?.length"
                      :tags="record?.businessModuleNameList"
                      :show-count="2"
                      :column-width="columnWidth"
                    />
                    <div v-else>-</div>
                  </template>
                  
 onMounted(() => {
  columnWidth.value = columns.find(
    (column) => column.key === 'businessModuleList'
  ).width