![](https://i-blog.csdnimg.cn/blog_migrate/b657ef9ed7707553453db751ccbeebc8.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4567d08f340f37b4e86d905215e96f08.png)
标签宽度不固定,想要实现超出一行后就自动折叠,并在后面跟上折叠/展开按钮,当标签总长度不足一行时不显示按钮,超过一行时折叠并显示按钮
话不多说,直接上代码
<template>
<ul class="sub-nav">
//这块的v-show显示条件是data,isFold(属于展开状态)||(或者)index(下标)<data.foldIndex(当前我所记录单行可以展示的数量)
<li v-for="(item,index) in data.keywordList" :key="index" v-show="index < data.foldIndex||data.isFold"
:class="data.keyword==item?'active-li sub-nav-list':'sub-nav-list'" @click="handleCutKey(item)">
{{item}}
</li>
<li class="btn" ref="fold" @click="data.isFold=!data.isFold"
:style="data.isFold?{position:'unset'}:{position:'absolute'}">
{{data.isFold?'折叠':'展开'}}<img :style="{transform:data.isFold?'rotate(90deg)':'rotate(-90deg)'}"
src="@/assets/image/返回键.png" alt="">
</li>
</ul>
</template>
<script setup lang="ts">
const data = reactive({
// 关键词分类
keywordList: string[] = [];
// 当前选中的关键词
keyword: string = '';
// 是否折叠关键词
isFold: boolean = false;
// 折叠展示到的下标
foldIndex: number = 100;
})
const fold = ref < HTMLElement | null > (null)
onMounted(() => {
getData()
})
// 获取数据
const getData = () => {
data.keywordList = ['热门', '人物', '萌宠', '美妆', '足球盛宴', '旅行', '汽车', '穿搭']
data.keyword = data.keywordList[0]
let boxWidth = document.querySelector('.sub-nav').offsetWidth
let arr = document.querySelectorAll('.sub-nav-list')
let btnWidth = fold.value.offsetWidth
variable(boxWidth, arr, btnWidth)
.then(res => {
data.foldIndex = res
console.log(res)
})
.catch(error => {
// 此处不足一行时我将按钮隐藏了
fold.value.style.display = error
console.error(error);
});
}
// 封装可折叠标签组件
const variable = (boxWidth: number, arr: HTMLElement[] | null, btnWidth: number) => {
// boxWidth -- 盒子宽度 arr -- 要处理的dom列表 btnWidth -- 展开/折叠按钮的宽度
return new Promise((resolve, reject) => {
let array = Array.from(arr) //
// 求出元素叠加后的总长度
// 使用reduce方法计算总和
let sum = array.reduce((acc, obj) => {
return acc + obj.offsetWidth;
}, 0);
if (sum > boxWidth) {
// 元素总长度大于盒子宽度
let total = 0;
let index = 0;
for (let i = 0; i < array.length; i++) {
total += array[i].offsetWidth;
if (total >= boxWidth - btnWidth) {
index = i;
break;
}
}
// 返回应该展示的标签数量
resolve(parseInt(index));
} else {
// 元素总长度小于盒子宽度
console.log('小')
reject('none');
}
});
}
// 切换关键词
const handleCutKey = (item: string) => {
data.keyword = item
}
</script>
<style scoped lang="scss">
.sub-nav {
width: 100%;
display: flex;
align-items: center;
flex-wrap: wrap;
margin-top: 0.1rem;
padding: 0 0.1rem;
position: relative;
li {
display: flex;
align-items: center;
//此处记得用padding来留出和右边标签之间的距离
padding-right: .2rem;
font-size: .12rem;
white-space: nowrap;
color: #999999;
cursor: pointer;
padding-bottom: .1rem;
user-select: none;
}
.active-li {
color: #E80000;
padding-bottom: .1rem;
}
.btn {
color: #5764FF;
position: absolute;
right: 0;
top: 0;
img {
margin-left: 0.05rem;
width: 0.06rem;
transform: rotate(-90deg);
}
}
}
</style>
现在单位经常会出这样的需求,有这种交互方式,功能很小,但挺麻烦,今天 索性就直接简单封装了一下,主要方法variable(),完整代码就这样,有问题评论区联系吧