vue tag 实现类似效果:
先计算tag字内容的长度
//text 为内容
//font 为文字大小和字体
const getTextWidth = (text, font = '12px Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif') => {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
context.font = font;
const metrics = context.measureText(text);
//12为tag的左右padding ---- 根据情况而定
return metrics.width + 20;
}
后通过字的宽度计算是否超出容器
const getVisibleTagBox = () => {
let totalWidth = 0;
//64为是否有更多盒子预留间距
const maxWidth = TagItemBox.value.offsetWidth - 64; // 获取容器宽度
VisibleTag.value = tags.value.filter((box => {
if(box){
// 每个盒子有8的边距 如果每个容器中有间距改成特定的间距这里间距是8
const boxWidth = getTextWidth(box) + 8
const willFit = totalWidth + boxWidth <= maxWidth;
if (willFit) {
totalWidth +=boxWidth;
}
return willFit;
}
}))
hasMore.value = tags.value.length > VisibleTag.value.length;
if(hasMore.value) {
// 隐藏的盒子取显示盒子后面的数据
hideTage.value = tags.value.slice(VisibleTag.value.length)
}
}
完整代码
<template>
<div style="width: 300px;display: flex;gap: 8px;" ref="TagItemBox">
<el-tag v-for="(item,index) in VisibleTag" :key="index" type="success">{{item}}</el-tag>
<template v-if="hasMore ">
<el-popover placement="bottom" trigger="hover" width="auto">
<template #reference>
<el-tag>・・・</el-tag>
</template>
<span style="gap: 8px;display: flex;">
<el-tag v-for="(item,index) in hideTage" :key="index" type="success">{{item}}</el-tag>
</span>
</el-popover>
</template>
</div>
</template>
<script setup>
import { onMounted,ref,nextTick } from 'vue'
const tags = ref(['标签一','标签一二','标签一二三','标签二三','标签四'])
const TagItemBox = ref(null)
const hasMore = ref(false)// 是否有更多盒子需要显示
const VisibleTag = ref([]) // 当前显示的盒子
const hideTage = ref([])// 当前隐藏的盒子
// 获取文字宽度 + 20 为左右边距
const getTextWidth = (text, font = '12px Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif') => {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
context.font = font;
const metrics = context.measureText(text);
return metrics.width + 20;
}
const getVisibleTagBox = () => {
let totalWidth = 0;
const maxWidth = TagItemBox.value.offsetWidth - 64; // 获取容器宽度
VisibleTag.value = tags.value.filter((box => {
if(box){
// 每个盒子有8的边距
const boxWidth = getTextWidth(box) + 8
const willFit = totalWidth + boxWidth <= maxWidth;
if (willFit) {
totalWidth +=boxWidth;
}
return willFit;
}
}))
hasMore.value = tags.value.length > VisibleTag.value.length;
if(hasMore.value) {
// 隐藏的盒子取显示盒子后面的数据
const uniqueData = tags.value.filter((item) => {
const found = VisibleTag.value.find((i) => i === item);
return !found;
});
hideTage.value = uniqueData
}
}
onMounted(()=>{
nextTick(()=>{
getVisibleTagBox()
})
})
</script>
有些参数可能有一些问题,使用时根据情况而定