guyu/components/guyu/home/tabs.vue
2025-07-25 13:27:18 +08:00

192 lines
4.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="tabs-container">
<view class="tabs-wrapper">
<template v-for="(item, index) in slideLableList" :key="index">
<view class="tab-item-wrapper" @click="clickTab(index)" :style="{ width: item.width }">
<SlideLabel ref="slideLabels" :defaultColor="item.active ? '#F5D677' : '#fff'">
<text class="tab-text myZt-500w">{{ item.name }}</text>
</SlideLabel>
</view>
</template>
</view>
</view>
</template>
<script setup>
import { onMounted, ref, watch, nextTick } from 'vue';
import SlideLabel from '@/components/guyu/page/slide-label.vue';
const props = defineProps({
list: {
type: Array,
default: () => []
},
current: {
type: Number,
default: 0
},
});
// 滑动方向1表示向右滑-1表示向左滑0表示初始状态
let slideDirection = ref(0);
// 标签列表
let slideLableList = ref([]);
// 滑块组件引用
let slideLabels = ref([]);
// 初始化和更新slideLableList的函数
const initSlideLableList = () => {
slideLableList.value = props.list.map((item, index) => {
return {
name: item.name,
width: getLableWidth(item.name),
active: index === props.current,
data: item
}
});
// 确保DOM更新后再操作SlideLabel实例
nextTick(() => {
updateLabelsState();
});
}
// 监听props.list的变化
watch(() => props.list, () => {
initSlideLableList();
}, { deep: true });
// 监听current变化处理标签切换
watch(() => props.current, (newCurrent, oldCurrent) => {
if (newCurrent !== oldCurrent && slideLableList.value.length > 0) {
// 更新激活状态
slideLableList.value.forEach((item, index) => {
item.active = index === newCurrent;
});
// nextTick(() => {
// updateLabelsState();
// });
}
});
// 更新所有标签状态
const updateLabelsState = () => {
if (!slideLabels.value || slideLabels.value.length === 0) return;
// 重置所有标签状态
slideLabels.value.forEach((label, index) => {
if (label && label.reset) {
label.reset();
}
});
}
onMounted(() => {
initSlideLableList();
})
const getLableWidth = (name) => {
let t = name.length * 20 + 40;
if (t < 80) {
t = 80;
}
return t + "rpx";
}
const systemWidth = parseInt(uni.getWindowInfo().screenWidth * 0.96);
const emit = defineEmits(['change']);
let isClick = false;
// 点击标签
const clickTab = (index) => {
console.log('点击标签');
if (index == props.current) {
return;
}
isClick = true;
emit("change", index);
}
// 滑动效果处理函数
const setDx = (dx) => {
if (!slideLabels.value || slideLabels.value.length === 0 || isClick) return;
// console.log('滑动处理了');
// 计算滑动百分比(0-100)
const absDx = Math.abs(dx);
const percent = Math.min(100, Math.round((absDx / systemWidth) * 100));
// 确定滑动方向
const direction = dx > 0 ? 1 : (dx < 0 ? -1 : 0);
slideDirection.value = direction;
const currentIndex = props.current;
if (direction > 0 && currentIndex + 1 < slideLableList.value.length) {
// 向右滑动 - 当前标签颜色消失,下一标签颜色出现
const nextIndex = currentIndex + 1;
// 当前标签从右侧被透明覆盖
slideLabels.value[currentIndex]?.coverFromLeft('#fff', percent);
// 下一个标签从左侧被颜色覆盖
slideLabels.value[nextIndex]?.coverFromLeft('#F5D677', percent);
} else if (direction < 0 && currentIndex > 0) {
// 向左滑动 - 当前标签颜色消失,前一标签颜色出现
const prevIndex = currentIndex - 1;
// 当前标签从左侧被透明覆盖
slideLabels.value[currentIndex]?.coverFromRight('#fff', percent);
// 前一个标签从右侧被颜色覆盖
slideLabels.value[prevIndex]?.coverFromRight('#F5D677', percent);
}
}
// 滑动结束,重置状态
const unlockDx = () => {
slideDirection.value = 0;
if (isClick) {
isClick = false;
}
// 更新所有标签状态
nextTick(() => {
updateLabelsState();
// 确保当前选中的标签显示正确的颜色
slideLableList.value.forEach((item, index) => {
item.active = index === props.current;
});
});
}
// 暴露方法给父组件
defineExpose({
setDx,
unlockDx
});
</script>
<style lang="scss" scoped>
.tabs-container {
width: 100%;
}
.tabs-wrapper {
width: 100%;
display: flex;
flex-direction: row;
margin-top: 32.64rpx;
}
.tab-item-wrapper {
min-width: 80rpx;
margin-right: 26.39rpx;
text-align: center;
line-height: 40rpx;
height: 50rpx;
}
.tab-text {
font-size: 22rpx;
}
</style>