项目中有需求显示el-tag标签 内容超出需要显示省略号并且点击省略显示剩余标签

<template>
<div ref="tagContainer" class="tag-list">
<!-- 显示的标签 -->
<el-tag
v-for="(tag, index) in visibleTags"
:key="index"
class="tag-item"
@click.stop
>
{{ tag }}
</el-tag>
<!-- 如果有更多标签,则显示省略按钮和 Popover -->
<el-popover
v-if="showPopover"
placement="top"
trigger="click"
width="300px"
>
<template #reference>
<el-tag class="more-tag"><moreFilled /></el-tag>
</template>
<div class="flex flex-wrap gap-[4px] w-full">
<el-tag
v-for="(tag, index) in hiddenTags"
:key="index"
class="popover-tag"
>
{{ tag }}
</el-tag>
</div>
</el-popover>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, computed, onUnmounted } from "vue";
import moreFilled from "~icons/ep/more-filled";
// 定义 Props
const props = defineProps({
tags: {
type: Array<any>,
default: () => [] as any[]
}
});
// DOM 引用
const tagContainer = ref<HTMLDivElement | null>(null);
// 是否显示 Popover
const showPopover = ref(false);
// 可见标签和隐藏标签
const visibleTags = ref<string[]>([]);
const hiddenTags = ref<string[]>([]);
// 计算可见标签和隐藏标签
const calculateTags = () => {
if (!tagContainer.value) return;
const containerWidth = tagContainer.value.offsetWidth;
let totalWidth = 0;
visibleTags.value = [];
hiddenTags.value = [];
props.tags.forEach(tag => {
const tempSpan = document.createElement("span");
tempSpan.style.position = "absolute";
tempSpan.style.visibility = "hidden";
tempSpan.style.whiteSpace = "nowrap";
tempSpan.innerText = tag;
document.body.appendChild(tempSpan);
const tagWidth = tempSpan.offsetWidth + 22; // 加上一些 padding gap-4 和tag内置的padding9 9 + 9 + 4
document.body.removeChild(tempSpan);
if (totalWidth + tagWidth <= containerWidth) {
visibleTags.value.push(tag);
totalWidth += tagWidth;
} else {
hiddenTags.value.push(tag);
}
});
showPopover.value = hiddenTags.value.length > 0;
};
// 监听窗口大小变化重新计算
onMounted(() => {
calculateTags();
window.addEventListener("resize", calculateTags);
});
// 组件卸载时移除事件监听
onUnmounted(() => {
window.removeEventListener("resize", calculateTags);
});
</script>
<style lang="scss" scoped>
.tag-list {
display: flex;
gap: 4px;
align-items: center;
overflow: hidden;
}
.tag-item {
white-space: nowrap;
}
.more-tag {
cursor: pointer;
}
.popover-tag {
max-width: 100%; // 设置最大宽度,防止无限延伸
height: auto;
line-height: 24px;
word-break: break-all; // 强制单词内换行
white-space: normal; // 允许换行
}
</style>