uniapp中不到200行实现vant ui的tab组件,可左右滑动屏幕切换tab,可自动显示隐藏的tab
<view class="container">
<view class="main">
<scroll-view class="tabs" :scroll-x="true" :scroll-left="scrollLeft" :scroll-with-animation="true" :enable-flex="true">
<block v-for="(title, index) in tabs" :key="index">
<view class="item" @tap="changeTab(index)" :class="{ 'active': active === index }">
<text>{{ title }}</text>
</view>
</block>
<view class="line" :style="getLineStyles">
<text></text>
</view>
</scroll-view>
</view>
<view class="content" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend">
<view class="box">
<slot></slot>
</view>
</view>
</view>
<script>
export default {
props: {
tabs: {
type: Array,
required: true
}, //父组件传递进来的,tabTitle
active: {
type: Number,
required: true
}, //切换tab时的active值,全权交给父组件更新
scrollLeftAct: {
type: Number
}, //在到达某个active的时候scroll left
scrollRgihtAct: {
type: Number
} ////在到达某个active的时候scroll right
},
data() {
return {
scrollLeft: 0,
clientWidth: 0,
contentWidth: 0,
startX: 0,
currentX: 0,
deltaX: 0
}
},
created() {
const systemInfo = uni.getSystemInfoSync();
this.clientWidth = systemInfo.screenWidth;
this.contentWidth = this.tabs.length * 20 / 100 * this.clientWidth
},
computed: {
getLineStyles() {
return {
width: `20%`,
left: `${this.active * 20}%`
}
}
},
methods: {
scrollToLeft() {
this.scrollLeft = 0; // 设置滚动条位置为0,即最左边
},
scrollToRight() {
this.scrollLeft = this.contentWidth - this.clientWidth; // 滚动到最右边
console.log(this.scrollLeft);
},
changeTab(index) {
if (index === this.scrollLeftAct) {
this.scrollToLeft();
}
if (index === this.scrollRgihtAct) {
this.scrollToRight();
}
this.$emit('changeTab', index);
},
getLineMoveStyle(val, oval) {
const diff = (val - oval) * 100;
return {
right: diff + '%'
}
},
touchstart(event) {
// 获取触摸开始时的 X 坐标
this.startX = event.touches[0].clientX;
},
touchmove(event) {
// 获取触摸移动时的 X 坐标
this.currentX = event.touches[0].clientX;
// 计算滑动的距离
this.deltaX = this.currentX - this.startX;
},
touchend() {
if (Math.abs(this.deltaX) > 30) {
// 向右滑动
if (this.deltaX > 0 && this.active > 0) {
setTimeout(() => {
this.changeTab(this.active - 1);
});
}
// 向左滑动
if (this.deltaX < 0 && this.active < this.tabs.length - 1) {
setTimeout(() => {
this.changeTab(this.active + 1);
});
}
}
this.deltaX = 0;
},
}
}
</script>
<style scoped>
.container {
height: 100%;
width: 100%;
}
.main {
position: fixed;
width: 100%;
}
.tabs {
height: 82upx;
position: relative;
overflow-x: auto;
overflow-y: hidden;
white-space: nowrap;
}
.item {
display: inline-block;
text-align: center;
width: 20%;
flex-shrink: 0;
font-size: 28upx;
color: #666666;
}
.active {
color: #000;
position: relative;
bottom: 4upx;
font-weight: bold;
font-size: 32upx;
}
.line {
position: absolute;
top: 32upx;
text-align: center;
transition: all .2s;
}
.line text {
display: inline-block;
width: 36upx;
height: 8upx;
border-radius: 32upx;
background-color: #FF483C;
}
.content {
width: 100%;
height: 100%;
box-sizing: border-box;
padding-top: 90upx;
}
.box {
width: 100%;
height: 100%;
overflow: hidden;
}
</style>
在父组件中
tabs @changeTab="changeTab" :active="active" :tabs="tabTitles" :scrollLeftAct="2" :scrollRgihtAct="4">
<empty v-if="orderList.length === 0" content="暂无订单" />
<order-list v-else />
</tabs>
data() {
return {
active: 0,
tabTitles: [
"全部",
"待邮寄",
"待验机",
"待确认",
"完成",
"已取消",
"已取消",
],
}
}