| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 | 
							- <!-- tab组件: <me-tabs v-model="tabIndex" :tabs="tabs" @change="tabChange"></me-tabs> -->
 
- <template>
 
- 	<view class="me-tabs" :class="{'tabs-fixed': fixed}" :style="{height: tabHeightVal, top:topFixed, 'margin-top':topMargin}">
 
- 		<scroll-view v-if="tabs.length" :id="viewId" :scroll-left="scrollLeft" scroll-x scroll-with-animation :scroll-animation-duration="300">
 
- 			<view class="tabs-item" :class="{'tabs-flex':!isScroll, 'tabs-scroll':isScroll}">
 
- 				<!-- tab -->
 
- 				<view class="tab-item" :style="{width: tabWidthVal, height: tabHeightVal, 'line-height':tabHeightVal}" v-for="(tab, i) in tabs" :class="{'active': value===i}" :key="i" @click="tabClick(i)">
 
- 					{{getTabName(tab)}}
 
- 					<!-- {{tab.gameName}} -->
 
- 				</view>
 
- 				<!-- 下划线 -->
 
- 				<!-- <view class="tabs-line" :style="{left:lineLeft}"></view> -->
 
- 			</view>
 
- 		</scroll-view>
 
- 	</view>
 
- </template>
 
- <script>
 
- 	export default {
 
- 		props:{
 
- 			tabs: { // 支持格式: ['全部', '待付款'] 或 [{name:'全部'}, {name:'待付款'}]
 
- 				type: Array,
 
- 				default(){
 
- 					return []
 
- 				}
 
- 			},
 
- 			nameKey: { // 取name的字段
 
- 				type: String,
 
- 				default: 'name'
 
- 			},
 
- 			value: { // 当前显示的下标 (使用v-model语法糖: 1.props需为value; 2.需回调input事件)
 
- 				type: [String, Number],
 
- 				default: 0
 
- 			},
 
- 			fixed: Boolean, // 是否悬浮,默认false
 
- 			tabWidth: Number, // 每个tab的宽度,默认不设置值,为flex平均分配; 如果指定宽度,则不使用flex,每个tab居左,超过则水平滑动(单位默认rpx)
 
- 			height: { // 高度,单位rpx
 
- 				type: Number,
 
- 				default: 80
 
- 			},
 
- 			top: { // 顶部偏移的距离,默认单位rpx (当fixed=true时,已加上windowTop)
 
- 				type: Number,
 
- 				default: 0
 
- 			}
 
- 		},
 
- 		data() {
 
- 			return {
 
- 				viewId: 'id_' + Math.random().toString(36).substr(2,16),
 
- 				scrollLeft: 0,
 
- 				windowWidth: 0,
 
- 				windowTop: 0
 
- 			}
 
- 		},
 
- 		computed: {
 
- 			isScroll(){
 
- 				return this.tabWidth && this.tabs.length // 指定了tabWidth的宽度,则支持水平滑动
 
- 			},
 
- 			tabHeightPx(){
 
- 				return uni.upx2px(this.height)
 
- 			},
 
- 			tabHeightVal(){
 
- 				return this.tabHeightPx+'px'
 
- 			},
 
- 			tabWidthPx(){
 
- 				return uni.upx2px(this.tabWidth)
 
- 			},
 
- 			tabWidthVal(){
 
- 				return this.isScroll ? this.tabWidthPx+'px' : ''
 
- 			},
 
- 			lineLeft() {
 
- 				if (this.isScroll) {
 
- 					return this.tabWidthPx * this.value + this.tabWidthPx/2 + 'px' // 需转为px (用rpx的话iOS真机显示有误差)
 
- 				} else{
 
- 					return 100/this.tabs.length*(this.value + 1) - 100/(this.tabs.length*2) + '%'
 
- 				}
 
- 			},
 
- 			topFixed(){
 
- 				return this.fixed ? this.windowTop + uni.upx2px(this.top) + 'px' : 0
 
- 			},
 
- 			topMargin(){
 
- 				return this.fixed ? 0 : this.top + 'rpx'
 
- 			}
 
- 		},
 
- 		watch: {
 
- 			tabs() {
 
- 				this.warpWidth = null; // 重新计算容器宽度
 
- 				this.scrollCenter(); // 水平滚动到中间
 
- 			},
 
- 			value() {
 
- 				this.scrollCenter(); // 水平滚动到中间
 
- 			}
 
- 		},
 
- 		created() {
 
- 			let sys = uni.getSystemInfoSync();
 
- 			this.windowWidth = sys.windowWidth
 
- 			this.windowTop = sys.windowTop
 
- 		},
 
- 		mounted() {
 
- 			this.scrollCenter() // 滚动到当前下标
 
- 		},
 
- 		methods: {
 
- 			getTabName(tab){
 
- 				return typeof tab === "object" ? tab[this.nameKey] : tab
 
- 			},
 
- 			tabClick(i){
 
- 				if(this.value!=i){
 
- 					this.$emit("input",i);
 
- 					this.$emit("change",i);
 
- 				}
 
- 			},
 
- 			async scrollCenter(){
 
- 				if(!this.isScroll) return;
 
- 				if(!this.warpWidth){ // tabs容器的宽度
 
- 					let rect = await this.initWarpRect()
 
- 					this.warpWidth = rect ? rect.width : this.windowWidth; // 某些情况下取不到宽度,暂时取屏幕宽度
 
- 				}
 
- 				let tabLeft = this.tabWidthPx * this.value + this.tabWidthPx/2; // 当前tab中心点到左边的距离
 
- 				let diff = tabLeft - this.warpWidth/2 // 如果超过tabs容器的一半,则滚动差值
 
- 				this.scrollLeft = diff;
 
- 				// #ifdef MP-TOUTIAO
 
- 				this.scrollTimer && clearTimeout(this.scrollTimer)
 
- 				this.scrollTimer = setTimeout(()=>{ // 字节跳动小程序,需延时再次设置scrollLeft,否则tab切换跨度较大时不生效
 
- 					this.scrollLeft = Math.ceil(diff)
 
- 				},400)
 
- 				// #endif
 
- 			},
 
- 			initWarpRect(){
 
- 				return new Promise(resolve=>{
 
- 					setTimeout(()=>{ // 延时确保dom已渲染, 不使用$nextclick
 
- 						let query = uni.createSelectorQuery();
 
- 						// #ifndef MP-ALIPAY
 
- 						query = query.in(this) // 支付宝小程序不支持in(this),而字节跳动小程序必须写in(this), 否则都取不到值
 
- 						// #endif
 
- 						query.select('#'+this.viewId).boundingClientRect(data => {
 
- 							resolve(data)
 
- 						}).exec();
 
- 					},20)
 
- 				})
 
- 			}
 
- 		}
 
- 	}
 
- </script>
 
- <style lang="scss">
 
- 	.me-tabs{
 
- 		position: relative;
 
- 		font-size: 30rpx;
 
- 		background: #FFFFFF;
 
- 		color: #999999;
 
- 		// border-bottom: 1rpx solid #eee;
 
- 		box-sizing: border-box;
 
- 		overflow-y: hidden;
 
- 		// padding: 0 10px ;
 
- 		&.tabs-fixed{
 
- 			z-index: 990;
 
- 			position: fixed;
 
- 			left: 0;
 
- 			width: 100%;
 
- 		}
 
- 		
 
- 		.tabs-item{
 
- 			position: relative;
 
- 			white-space: nowrap;
 
- 			// padding-bottom: 30rpx; // 撑开高度,再配合me-tabs的overflow-y: hidden,以达到隐藏滚动条的目的
 
- 			box-sizing: border-box;
 
- 			
 
- 			.tab-item{
 
- 				position: relative;
 
- 				text-align: center;
 
- 				box-sizing: border-box;
 
- 				margin: 0 15px;
 
- 				&.active{
 
- 					font-weight: bold;
 
- 					color: #000000;
 
- 					font-size: 32upx;
 
- 					border-bottom: 4upx solid #557EFD;
 
- 				}
 
- 			}
 
- 		}
 
- 		
 
- 		// 平分的方式显示item
 
- 		.tabs-flex{
 
- 			display: flex;
 
- 			.tab-item{
 
- 				flex: 1;
 
- 			}
 
- 		}
 
- 		// 居左显示item,支持水平滑动
 
- 		.tabs-scroll{
 
- 			.tab-item{
 
- 				display: inline-block;
 
- 			}
 
- 		}
 
- 		
 
- 		// 选中tab的线
 
- 		.tabs-line{
 
- 			z-index: 1;
 
- 			position: absolute;
 
- 			bottom: 30rpx; // 至少与.tabs-item的padding-bottom一致,才能保证在底部边缘
 
- 			width: 50rpx;
 
- 			height: 6rpx;
 
- 			transform: translateX(-50%);
 
- 			border-radius: 4rpx;
 
- 			transition: left .3s;
 
- 			background: #1789FD;
 
- 		}
 
- 	}
 
- </style>
 
 
  |