vue不使用组件库的情况下展示同时多个tab并在超出宽度的时候显示箭头可以切换上一页下一页
时间: 2023-12-05 17:19:13 浏览: 195
基于vue多tab页实现
不使用组件库也可以实现tab切换的功能,具体思路是通过计算tab的宽度和可视区域的宽度,动态计算左右箭头的显示和隐藏,并且通过点击箭头来实现切换上一页下一页的功能。
具体实现步骤如下:
1. 在Vue组件中定义tab的数据和当前显示的tab的索引
```html
<template>
<div class="tab-container">
<div class="tab-nav">
<div class="tab-nav-wrap" :style="{ transform: `translateX(-${tabWrapOffset}px)` }">
<div class="tab-nav-item" v-for="(tab, index) in tabs" :key="tab.name" :class="{ active: activeTab === index }" @click="handleTabClick(index)">
{{ tab.title }}
<span class="close" @click="handleTabClose(index)">×</span>
</div>
</div>
<div class="tab-nav-prev" :class="{ disabled: prevDisabled }" @click="handlePrevClick"><</div>
<div class="tab-nav-next" :class="{ disabled: nextDisabled }" @click="handleNextClick">></div>
</div>
<div class="tab-content">
{{ tabs[activeTab].content }}
</div>
</div>
</template>
<script>
export default {
data() {
return {
activeTab: 0,
tabs: [
{ name: 'tab1', title: '标签页1', content: '标签页1的内容' },
{ name: 'tab2', title: '标签页2', content: '标签页2的内容' },
{ name: 'tab3', title: '标签页3', content: '标签页3的内容' },
{ name: 'tab4', title: '标签页4', content: '标签页4的内容' },
{ name: 'tab5', title: '标签页5', content: '标签页5的内容' },
{ name: 'tab6', title: '标签页6', content: '标签页6的内容' },
{ name: 'tab7', title: '标签页7', content: '标签页7的内容' },
{ name: 'tab8', title: '标签页8', content: '标签页8的内容' },
{ name: 'tab9', title: '标签页9', content: '标签页9的内容' },
{ name: 'tab10', title: '标签页10', content: '标签页10的内容' },
{ name: 'tab11', title: '标签页11', content: '标签页11的内容' },
{ name: 'tab12', title: '标签页12', content: '标签页12的内容' },
{ name: 'tab13', title: '标签页13', content: '标签页13的内容' },
{ name: 'tab14', title: '标签页14', content: '标签页14的内容' },
{ name: 'tab15', title: '标签页15', content: '标签页15的内容' },
],
tabWrapOffset: 0, // tab导航栏的偏移量
prevDisabled: true, // 左箭头是否禁用
nextDisabled: false, // 右箭头是否禁用
};
},
mounted() {
this.handleResize();
window.addEventListener('resize', this.handleResize);
},
beforeDestroy() {
window.removeEventListener('resize', this.handleResize);
},
methods: {
handleTabClick(index) {
this.activeTab = index;
},
handleTabClose(index) {
this.tabs.splice(index, 1);
if (this.activeTab > index) {
this.activeTab -= 1;
} else if (this.activeTab === index && index === this.tabs.length) {
this.activeTab -= 1;
}
this.updateTabWrapOffset();
},
handleResize() {
this.updateTabWrapOffset();
},
updateTabWrapOffset() {
const tabNavWrap = this.$el.querySelector('.tab-nav-wrap');
const tabNavItems = tabNavWrap.querySelectorAll('.tab-nav-item');
let offset = 0;
for (let i = 0; i < this.activeTab; i++) {
offset += tabNavItems[i].offsetWidth;
}
this.tabWrapOffset = offset;
this.updateArrowDisabled();
},
updateArrowDisabled() {
const tabNav = this.$el.querySelector('.tab-nav');
const tabNavWrap = this.$el.querySelector('.tab-nav-wrap');
const tabNavPrev = this.$el.querySelector('.tab-nav-prev');
const tabNavNext = this.$el.querySelector('.tab-nav-next');
const offsetLeft = tabNavWrap.getBoundingClientRect().left - tabNav.getBoundingClientRect().left;
const offsetRight = tabNavWrap.getBoundingClientRect().right - tabNav.getBoundingClientRect().right;
this.prevDisabled = offsetLeft >= 0;
this.nextDisabled = offsetRight <= 0;
},
handlePrevClick() {
const tabNavWrap = this.$el.querySelector('.tab-nav-wrap');
const tabNavItems = tabNavWrap.querySelectorAll('.tab-nav-item');
let offset = this.tabWrapOffset;
for (let i = this.activeTab - 1; i >= 0; i--) {
offset -= tabNavItems[i].offsetWidth;
if (offset < 0) {
this.tabWrapOffset = Math.max(0, this.tabWrapOffset + offset);
this.updateArrowDisabled();
break;
}
}
},
handleNextClick() {
const tabNavWrap = this.$el.querySelector('.tab-nav-wrap');
const tabNavItems = tabNavWrap.querySelectorAll('.tab-nav-item');
let offset = this.tabWrapOffset;
for (let i = this.activeTab; i < this.tabs.length; i++) {
offset += tabNavItems[i].offsetWidth;
if (offset > tabNavWrap.offsetWidth) {
this.tabWrapOffset = Math.min(offset - tabNavWrap.offsetWidth, this.tabWrapOffset + offset - tabNavWrap.offsetWidth);
this.updateArrowDisabled();
break;
}
}
},
},
};
</script>
<style>
.tab-container {
width: 400px;
height: 300px;
}
.tab-nav {
display: flex;
justify-content: space-between;
align-items: center;
overflow: hidden;
}
.tab-nav-wrap {
display: flex;
transition: transform 0.3s;
}
.tab-nav-item {
position: relative;
padding: 10px;
cursor: pointer;
transition: color 0.3s;
}
.tab-nav-item.active {
color: #1890ff;
}
.tab-nav-item .close {
position: absolute;
top: 0;
right: 0;
padding: 5px;
cursor: pointer;
}
.tab-nav-prev,
.tab-nav-next {
width: 20px;
height: 20px;
border-radius: 50%;
font-size: 12px;
text-align: center;
line-height: 20px;
cursor: pointer;
background-color: #eee;
}
.tab-nav-prev:hover,
.tab-nav-next:hover {
background-color: #ddd;
}
.tab-nav-prev.disabled,
.tab-nav-next.disabled {
cursor: not-allowed;
background-color: #ccc;
}
</style>
```
在上面的代码中,我们通过计算tab导航栏的偏移量来实现tab的横向滚动,同时通过`updateArrowDisabled`方法来动态更新左右箭头的禁用状态,通过`handlePrevClick`和`handleNextClick`方法来实现切换上一页下一页的功能。在点击tab和关闭tab时,我们需要动态更新activeTab的值和tabs数组的内容,并且重新计算tab导航栏的偏移量。
另外,我们还需要在组件mounted和beforeDestroy钩子中监听窗口大小的变化,并且在窗口大小变化时重新计算tab导航栏的偏移量。
阅读全文