目录
- 自定义tabs+索引列表,支持左右滑动切换
- 创建scroll-x-tabs组件
- 创建touch-list组件
- 父组件使用
自定义tabs+索引列表,支持左右滑动切换
创建scroll-x-tabs组件
<view class="container"><scroll-viewclass="scroll-view"scroll-x="true":scroll-left="scrollLeft"scroll-with-animationshow-scrollbar="false"><viewv-for="(item, index) in list":key="`${item.dictValue}-${index}-${item.dictCode}`"class="scroll-item"@click="handleItemClick(index)":style="{color:(index === currentIndex ? computedActiveColor : computedColor) +' !important',}"><text>{{ item.dictLabel }}</text></view><viewv-if="list.length"class="indicator":style="{...indicatorStyle,background: lineColor,height: lineHeight,borderRadius: lineBorderRadius,}"></view></scroll-view></view>
props: {list: {type: Array,default: () => [],},color: {type: String,default: null,},activeColor: {type: String,default: null,},lineColor: {type: String,default: "rgba(0,0,0,0.5)",},lineHeight: {type: String,default: "6rpx",},lineBorderRadius: {type: String,default: "3rpx",},currentIndex: {type: Number,default: 0,},},data() {return {itemWidths: [], containerWidth: 0, scrollLeft: 0,indicatorLeft: 0,indicatorWidth: 60,};},computed: {...mapGetters(["appTheme"]),computedColor() {if (this.color) return this.color;return this.appTheme === "dark" ? "#999999" : "#333333";},computedActiveColor() {if (this.activeColor) return this.activeColor;return this.appTheme === "dark" ? "#ffffff" : "#000000";},indicatorStyle() {return {width: this.itemWidths[this.currentIndex]? `${this.itemWidths[this.currentIndex]}px`: "60px",transform: `translateX(${this.calculateIndicatorPosition()}px)`,};},},watch: {list: {handler() {this.$nextTick(() => {this.getItemWidths();});},deep: true,},currentIndex: {handler(newIndex) {this.$nextTick(() => {this.calculateScrollPosition();});},},},mounted() {this.getItemWidths();},methods: {getItemWidths(index = 0) {this.$nextTick(() => {const query = uni.createSelectorQuery().in(this);query.select(".scroll-view").boundingClientRect((containerData) => {if (containerData) {this.containerWidth = containerData.width;}}).exec();query.selectAll(".scroll-item").boundingClientRect((data) => {console.log("getItemWidths data", data);if (data) {this.itemWidths = data.map((item) => item.width);this.calculateScrollPosition();}}).exec();});},calculateScrollPosition() {let totalWidth = 0;for (let i = 0; i < this.currentIndex; i++) {totalWidth += this.itemWidths[i] || 120; }const currentItemWidth = this.itemWidths[this.currentIndex] || 120;const targetPosition = totalWidth + currentItemWidth / 2;this.scrollLeft = Math.max(0, targetPosition - this.containerWidth / 2);},calculateIndicatorPosition() {let totalWidth = 0;for (let i = 0; i < this.currentIndex; i++) {totalWidth += this.itemWidths[i] || 120;}return totalWidth;},handleItemClick(index) {this.$emit("update:currentIndex", index);this.$emit("onHandleItemClick", index);this.$nextTick(() => {this.calculateScrollPosition();});},},
.container {width: 100%;padding: 10rpx 0;
}.scroll-view {width: 100%;white-space: nowrap;height: 80rpx;box-sizing: border-box;
}.scroll-item {display: inline-block;padding: 0 30rpx;height: 70rpx;line-height: 70rpx;text-align: center;font-size: 30rpx;color: #333;
}.indicator {transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
创建touch-list组件
<swiperclass="swiper-container":current="currentIndex"@change="handleSwiperChange":duration="300":style="{ height: swiperHeight }"><swiper-itemv-for="(item, index) in listLength":key="index"class="swiper-item"><view class="content" v-if="index === currentIndex"><slot></slot></view></swiper-item></swiper>
props: {currentIndex: {type: Number,default: 0,},listLength: {type: Number,default: 0,},swiperHeight: {type: String,default: "500rpx",},},methods: {handleSwiperChange(e) {this.$emit("update:currentIndex", e.detail.current);this.$emit("onHandleSwiperChange", e.detail.current);},},
.swiper-container {width: 100%;
}.swiper-item {width: 100%;height: 100%;
}.content {width: 100%;height: 100%;overflow: scroll;
}
父组件使用
<scroll-x-tabs:list="exploreTypeDictList":currentIndex.sync="current":line-color="lineColor"></scroll-x-tabs><touch-list:list-length="exploreTypeDictList.length":currentIndex.sync="current":swiperHeight="swiperHeight"@onHandleSwiperChange="onHandleSwiperChange"
><view class="learn-grid" v-if="studyList.length"></view></touch-list>