zn-admin-vue3-wcs/src/views/board/device/tabs.vue
2025-02-11 17:03:11 +08:00

171 lines
3.3 KiB
Vue

<template>
<div class="tabs-container">
<!-- 左箭头 -->
<div
v-if="showArrows && canScrollLeft"
class="arrow arrow-left"
@click="scrollLeft"
>left</div>
<!-- 滚动容器 -->
<div class="tabs-scroll" ref="scrollRef" @scroll="handleScroll">
<div class="tabs">
<div
v-for="(tab, index) in tabs"
:key="index"
:class="['tab-item', { active: activeTab === index }, tab.class]"
@click="setActiveTab(index)"
>
<slot :name="`tab-${index}`"></slot>
</div>
</div>
</div>
<!-- 右箭头 -->
<div
v-if="showArrows && canScrollRight"
class="arrow arrow-right"
@click="scrollRight"
>right</div>
<!-- 内容区域 -->
<div class="tabs-content">
<slot :name="`content-${activeTab}`"></slot>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, watch } from 'vue';
// 接收默认激活的 tab 索引
const props = defineProps({
defaultActiveTab: {
type: Number,
default: 0
}
});
// 当前激活的 tab 索引
const activeTab = ref(props.defaultActiveTab);
// 滚动容器的引用
const scrollRef = ref(null);
// 是否可以向左滚动
const canScrollLeft = ref(false);
// 是否可以向右滚动
const canScrollRight = ref(false);
// 是否显示箭头
const showArrows = ref(false);
// 设置激活的 tab
const setActiveTab = (index) => {
activeTab.value = index;
};
// 收集所有 tab 项
const tabs = [];
const slots = useSlots();
for (const key in slots) {
if (key.startsWith('tab-')) {
const index = parseInt(key.split('-')[1]);
const classProp = slots[`class-${index}`]?.()[0]?.props?.innerHTML;
tabs[index] = { class: classProp };
}
}
// 处理滚动事件
const handleScroll = () => {
const scrollEl = scrollRef.value;
canScrollLeft.value = scrollEl.scrollLeft > 0;
canScrollRight.value = scrollEl.scrollLeft < scrollEl.scrollWidth - scrollEl.clientWidth;
};
// 向左滚动
const scrollLeft = () => {
const scrollEl = scrollRef.value;
scrollEl.scrollLeft -= 200;
};
// 向右滚动
const scrollRight = () => {
const scrollEl = scrollRef.value;
scrollEl.scrollLeft += 200;
};
const checkArrowsVisibility = () => {
const scrollEl = scrollRef.value;
showArrows.value = scrollEl.scrollWidth > scrollEl.clientWidth;
};
onMounted(() => {
checkArrowsVisibility();
handleScroll();
});
// 监听滚动容器宽度变化
watch(
() => scrollRef.value?.scrollWidth,
() => {
checkArrowsVisibility();
handleScroll();
}
);
</script>
<style scoped>
.tabs-container {
position: relative;
width: 100%;
}
.arrow {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 30px;
height: 30px;
background-color: rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
z-index: 1;
}
.arrow-left {
left: 0;
}
.arrow-right {
right: 0;
}
.tabs-scroll {
width: 100%;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
scroll-behavior: smooth;
scrollbar-width: none;
-ms-overflow-style: none;
}
.tabs-scroll::-webkit-scrollbar {
display: none;
}
.tabs {
display: flex;
white-space: nowrap;
}
.tab-item {
padding: 10px 15px;
cursor: pointer;
}
.tab-item.active {
font-weight: bold;
}
.tabs-content {
padding: 15px;
border-top: 1px solid #eee;
}
</style>