142 lines
2.9 KiB
Vue
142 lines
2.9 KiB
Vue
<template>
|
||
<view class="category-tabs-container">
|
||
<scroll-view
|
||
class="category-scroll"
|
||
scroll-x
|
||
:scroll-left="scrollLeft"
|
||
:scroll-with-animation="true"
|
||
:show-scrollbar="false"
|
||
>
|
||
<view class="category-list">
|
||
<view
|
||
v-for="(category, index) in categories"
|
||
:key="category.id"
|
||
class="category-item"
|
||
:class="{ active: activeCategory?.id === category.id }"
|
||
@click="handleCategoryClick(category, index)"
|
||
>
|
||
<text class="category-name">{{ category.name }}</text>
|
||
<view class="category-indicator" v-if="activeCategory?.id === category.id"></view>
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
name: 'ProjectCategoryTabs',
|
||
props: {
|
||
// 分类列表
|
||
categories: {
|
||
type: Array,
|
||
default: () => []
|
||
},
|
||
// 当前选中的分类
|
||
activeCategory: {
|
||
type: Object,
|
||
default: null
|
||
}
|
||
},
|
||
data() {
|
||
return {
|
||
scrollLeft: 0
|
||
}
|
||
},
|
||
watch: {
|
||
activeCategory: {
|
||
handler(newVal) {
|
||
if (newVal && this.categories.length > 0) {
|
||
this.scrollToActiveCategory()
|
||
}
|
||
},
|
||
immediate: true
|
||
}
|
||
},
|
||
methods: {
|
||
handleCategoryClick(category, index) {
|
||
this.$emit('change', category)
|
||
|
||
// 滚动到选中的分类
|
||
this.scrollToIndex(index)
|
||
},
|
||
|
||
scrollToIndex(index) {
|
||
// 计算需要滚动的距离
|
||
// 这里简化处理,实际可以根据元素宽度计算
|
||
const itemWidth = 120 // 每个分类项的预估宽度(rpx)
|
||
const scrollViewWidth = 750 // scroll-view宽度(rpx)
|
||
const targetLeft = index * itemWidth - scrollViewWidth / 2 + itemWidth / 2
|
||
|
||
this.scrollLeft = Math.max(0, targetLeft)
|
||
},
|
||
|
||
scrollToActiveCategory() {
|
||
const index = this.categories.findIndex(cat => cat.id === this.activeCategory?.id)
|
||
if (index !== -1) {
|
||
this.scrollToIndex(index)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.category-tabs-container {
|
||
width: 100%;
|
||
background-color: #fff;
|
||
border-bottom: 1rpx solid #f0f0f0;
|
||
}
|
||
|
||
.category-scroll {
|
||
width: 100%;
|
||
white-space: nowrap;
|
||
height: 90rpx;
|
||
}
|
||
|
||
.category-list {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
height: 100%;
|
||
padding: 0 30rpx;
|
||
}
|
||
|
||
.category-item {
|
||
position: relative;
|
||
padding: 0 30rpx;
|
||
height: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.category-name {
|
||
font-size: 30rpx;
|
||
color: #666;
|
||
font-weight: 400;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.category-item.active .category-name {
|
||
color: #3cc51f;
|
||
font-weight: 500;
|
||
font-size: 32rpx;
|
||
}
|
||
|
||
.category-indicator {
|
||
position: absolute;
|
||
bottom: 0;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
width: 40rpx;
|
||
height: 4rpx;
|
||
background-color: #3cc51f;
|
||
border-radius: 2rpx;
|
||
}
|
||
|
||
/* 点击效果 */
|
||
.category-item:active {
|
||
opacity: 0.7;
|
||
}
|
||
</style> |