小程序 封装的 滑动tab 切换

<template>
	<view class="tab-page-root">
		<view class="tabbar-header flex_align-center">
			<view v-for="(item,i) in tabs" @tap="tabTap(i)" class="flex1" :key="item">{{item}}</view>
		</view>
		<view :style="{left:tabLineLeft+'px'}" class="tabbar-line"></view>
		<view class="tabbar-content" :style="'transform:translateX('+xPercent+'%);transition:transform '+pageDuration+'ms;'"
		 @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend">
			<view v-for="(item, i) in tabs" :key="item" :style="'transform:translateX('+i*100+'%)'" class="tabbar-page">
				<slot name="page" :i="i" :pageData="pageData"></slot>
			</view>
		</view>
	</view>
</template>

<script>
	const safeAreaWidth = uni.getSystemInfoSync().safeArea.width
	let tabbarLineWidth,
		yAxisGap = 8
	// #ifdef H5
	yAxisGap = 6
	// #endif
	export default {
		props: {
			tabs: {
				type: Array,
				required: true
			},
			pageData: ''
		},

		data() {
			return {
				tabIndex: 0,
				xPercent: 0,
				startPageX: 0,
				startPageY: 0,
				yScrollTimes: 0,
				yScrolling: false,
				positive: 1,
				pageDuration: 0,
				tabLineLeft: safeAreaWidth / this.tabs.length - 17
			}
		},
		mounted() {
			uni.createSelectorQuery().in(this).select('.tabbar-line').boundingClientRect(data => { // data - 各种参数
      console.log(data);
				tabbarLineWidth = data.width
				this.tabLineLeft = (safeAreaWidth / this.tabs.length - tabbarLineWidth) / 2
			}).exec()
		},
    onReachBottom: function() {
    },
		methods: {
			tabTap(i) {
				if (this.tabIndex != i) {
					this.pageDuration = 0
					this.xPercent = -i * 100
					this.tabIndex = i
					this.tabLineLeft = (i + 1 / 2) * safeAreaWidth / this.tabs.length - tabbarLineWidth / 2
					this.loadTabPage()
				}
			},
			touchstart(e) {
				this.startPageX = e.changedTouches[0].pageX
				this.startPageY = e.changedTouches[0].pageY
				this.startXPercent = this.xPercent
			},
			touchmove(e) {
				this.yScrollTimes++
				if (this.yScrollTimes == 1 && Math.abs(e.changedTouches[0].pageY - this.startPageY) > yAxisGap) {
					this.yScrolling = true
				}
				if (this.yScrolling) return
				this.pageDuration = 0
				const relativeXPercent = (e.changedTouches[0].pageX - this.startPageX) * 100 / safeAreaWidth
				if (this.relativeXPercent < relativeXPercent) {
					this.positive = -1
				} else {
					this.positive = 1
				}
				const xPercent = relativeXPercent + this.startXPercent
				if (xPercent >= 0) {
					this.xPercent = 0
				} else if (xPercent <= (1 - this.tabs.length) * 100) {
					this.xPercent = (1 - this.tabs.length) * 100
				} else {
					this.xPercent = xPercent
				}
				this.relativeXPercent = relativeXPercent
			},
			touchend() {
				if (-this.xPercent % 100 < 10 || (this.relativeXPercent < 0 && this.positive < 0)) {
					this.pageDuration = 80
					this.tabIndex = Math.floor(-this.xPercent / 100)
				} else if (-this.xPercent % 100 > 90 || (this.relativeXPercent > 0 && this.positive > 0)) {
					this.pageDuration = 80
					this.tabIndex = Math.floor(-this.xPercent / 100 + 1)
				} else {
					this.pageDuration = 300
					this.tabIndex += this.positive
					this.tabLineLeft = (this.tabIndex + 1 / 2) * safeAreaWidth / this.tabs.length - tabbarLineWidth / 2
					this.loadTabPage()
				}
				this.xPercent = -this.tabIndex * 100
				this.yScrolling = false
				this.yScrollTimes = 0
			},
			loadTabPage() {
				this.$emit('tabSwitch', this.tabIndex)
			}
		}
	}
</script>

<style>
	.flex_align-center {
		display: flex;
		align-items: center;
	}

	.flex1 {
		flex: 1;
	}

	.tab-page-root {
		position: absolute;
		width: 100%;
		height: 100%;
	}

	.tabbar-header {
		text-align: center;
		line-height: 72upx;
	}

	.tabbar-line {
		position: relative;
		left: 96upx;
		width: 80rpx;
		height: 8rpx;
		background-color: #000000;
		transition: left 300ms;
	}

	.tabbar-content {
		min-height: calc(100% - 83upx);
	}

	.tabbar-page {
		position: absolute;
		width: 100%;
		height: 100%;
		overflow-y: auto;
	}
</style>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值