[el-tag]使用多个el-tag,自动判断内容是否超出

项目中有需求显示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>
相关推荐
审小匠OpenCPAi17 分钟前
银行流水核查怎么自动化?单边匹配、双向勾稽与图聚类异常检测的工程对比
java·前端·人工智能·python·审计
Revolution6121 分钟前
一个公共表格组件,是怎么一步步失控的
前端·前端工程化
mONESY24 分钟前
React useState 核心原理与最佳实践:从异步更新到性能优化全解
javascript
腻害兔37 分钟前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:CRM 客户关系模块深度解析——从线索到回款,一套完整的 B2B 销售闭环是怎么搭的?
java·前端·javascript·vue.js·产品经理·ai编程
whyfail1 小时前
前端学 Spring Boot(2):一次点击,如何穿过整个后端?
前端·spring boot·后端
AI多Agent协作实战派1 小时前
AI多Agent协作系统实战(二十三):Agent读HEARTBEAT.md不读AGENTS.md——openclaw的文件加载之谜
前端·数据库·人工智能·uni-app
gis开发之家2 小时前
《Vue3 从入门到大神37篇》Vue3 源码详解(七):watch 与 watchEffect 源码对比——副作用是如何被追踪的?
javascript·前端框架·vue3·vue3源码
2601_955760072 小时前
如何用 Claude Opus 5 API 批量扩展长尾关键词和文章选题
前端·python·搜索引擎
KaMeidebaby2 小时前
卡梅德生物技术快报|bli亲和力检测gst:告别批量跑胶:BLI实时酶切监测技术加速GST融合蛋白下游流程优化
前端·网络·数据库·人工智能·算法
bloglin999993 小时前
langchain 和 langgraph 和 react
javascript·react.js·langchain