|
|
<template> <view class="tab-container"> <view class="tab-box"> <scroll-view id="_scroll" scroll-x class="scroll-view" scroll-with-animation :scroll-left="scrollLeft" > <view class="scroll-content"> <view class="tab-item-box"> <block v-for="(item, index) in tabList" :key="index"> <view class="tab-item" :id="'_tab_' + index" :class="{ 'tab-item-active': activeIndex === index }" @click="tabClick(index)" :style="{ color: activeIndex === index ? defaultConfig.activeTextColor : defaultConfig.textColor }" >{{ item.label || item }}</view> </block> </view>
<!-- 滑块 --> <view class="underLine" :style="{ transform: 'translateX(' + slider.left + 'px)', width: defaultConfig.underLineWidth + 'px', height: defaultConfig.underLineHeight + 'px', backgroundColor: defaultConfig.underLineColor }" /> </view> </scroll-view> </view> </view></template>
<script>export default { name: 'my-tabs', props: { tabData: { type: Array, default: () => [] }, defaultIndex: { type: Number, default: 0 }, config: { type: Object, default: () => ({}) } }, data() { return { tabList: [], activeIndex: 0, slider: { left: 0 }, scrollLeft: 0, defaultConfig: { textColor: '#333333', activeTextColor: '#01a4fe', underLineWidth: 24, underLineHeight: 2, underLineColor: '#01a4fe' } } }, watch: { tabData: { handler(val) { this.tabList = val this.$nextTick(() => { this.updateTabWidth() }) }, immediate: true }, defaultIndex: { handler(val) { if (this.tabList.length === 0) return this.activeIndex = val this.$nextTick(() => { this.updateTabWidth() }) }, immediate: true }, config: { handler(val) { this.defaultConfig = { ...this.defaultConfig, ...val } }, immediate: true } }, methods: { updateTabWidth() { if (this.tabList.length === 0) return
const query = uni.createSelectorQuery().in(this) let finishCount = 0
this.tabList.forEach((item, index) => { query.select(`#_tab_${index}`).boundingClientRect((res) => { if (!res) return item._slider = { left: res.left + (res.width - this.defaultConfig.underLineWidth) / 2 } finishCount++ if (finishCount === this.tabList.length) { this.tabToIndex() } }).exec() }) },
tabClick(index) { this.activeIndex = index this.tabToIndex() this.$emit('tabClick', index) },
tabToIndex() { if (!this.tabList.length || !this.tabList[this.activeIndex]?._slider) { return } this.slider.left = this.tabList[this.activeIndex]._slider.left } }}</script>
<style lang="scss" scoped>.tab-container { font-size: 14px; height: 45px; line-height: 45px;
.tab-box { width: 100%; height: 45px; display: flex; position: relative;
.scroll-view { white-space: nowrap; width: 100%; height: 100%; box-sizing: border-box;
.scroll-content { width: 100%; height: 100%; position: relative;
.tab-item-box { display: flex; justify-content: space-around; height: 100%;
.tab-item { height: 100%; display: inline-block; text-align: center; padding: 0 20px; position: relative; color: #333;
&-active { color: #01a4fe; } } } .underLine { height: 2px; width: 25px; background-color: #01a4fe; border-radius: 3px; transition: 0.3s; position: absolute; bottom: 0; } } } }
/* #ifdef H5 */ ::v-deep .uni-scroll-view::-webkit-scrollbar { display: none; } /* #endif */}</style>
|