实现效果如图
要实现底部内部的左右滑动切换带动上方tab栏的切换,并且下方内容要实现纵向滚动 ,所以需要swiper,swiper-item,scroll-view组合使用
tab栏部分
<view class="tabs"><view class="tab_item" v-for="(item,index) in tabList" :key="index" @click="tabSwitch(item,index)"><view class="tab_name" :class="activeTab==index?'act_name':''">{{item.name}}</view><view class="tab_cover" v-if="activeTab!=index"></view><image v-else :src="getimg('leaderboard_toggle.png')" style="width: 30rpx;height: 11rpx;"></image></view></view>
tab栏点击切换,需要重新调取数据
tabSwitch(item, index) {this.scrollTop = 0this.activeTab = index// this.dataList = []this.getData()},
下方内容部分
<swiper class="data_list" @change="swipeIndex" :current="activeTab":duration="300" previous-margin="0" :style="{ height: (pageHeight-205)+'px' }" :circular="true"><swiper-item v-for="(val,idx) in tabList" :key="idx"><scroll-view v-if="dataList.length>0" scroll-y="true" :style="{ height: (pageHeight-205)+'px' }":scroll-top="scrollTop"><view style="padding-bottom: 100rpx;"><view class="data_item" :class="index*1+1<4?'act_item'+(index*1+1):''"v-for="(item,index) in dataList" :key="index" @click="goDetail(item,index)"><view class="le"><image :src="getimg('Leaderboard_'+(index*1+1)+'.png')" mode="heightFix"style="height: 112rpx;"></image><view class="item_content">{{item.idea_name}}</view></view><view class="like_num">{{item.likecount}}</view></view></view></scroll-view><view v-else class="data_none" :style="{ height: (pageHeight-205)+'px' }"><image :src="getimg('null-page.png')" style="width: 380rpx;height: 380rpx;"></image><view class="nothing">空空如也~</view></view></swiper-item></swiper>
滑动切换,改变上方tab栏状态,并重新调取数据
swipeIndex(e){this.activeTab = e.detail.currentthis.scrollTop = 0this.getData()}
以上即可实现页面左右滑动切换带动tab栏切换
但是,上面这种方式适合tab栏目比较少,内容列表也比较短的情况,如果tab栏项目很多,内容数据也很多,用swiper做切换会很卡顿,这个官方地址也有介绍swiper | uni-app官网
我懒得去研究怎么去优化他,不过这个博主的优化方式很厉害,可以借鉴一下,附上地址:
uni-app swiper数量过多时卡顿优化方案_uniapp swiper卡顿_菜鸟驿站2020的博客-CSDN博客
所以当数据很多时,我使用了touch事件加动画的方式做切换
如图,tab栏选项很多,内容列表数据也很多
tabs部分
<view class="tab_box"><view style="max-width: 600rpx;height:80rpx ;"><u-tabs :list="tabsList" :current="actTab" keyName="category_name" @click="tabSwitch" lineWidth="20"lineHeight="4" lineColor="#000000":activeStyle="{color: '#000000',fontWeight: 'bold',transform: 'scale(1.4)'}":inactiveStyle="{color: '#666666',transform: 'scale(1.2)'}"></u-tabs></view><view class="more" @click="cateShow = true"><image :src="getimg('originality_label.png')" style="width: 50rpx;height: 50rpx;"></image></view></view>
列表部分
<view class="data_list" @touchstart="touchStart" @touchend="touchEnd" :animation="animationData" :style="{ height: (pageHeight-(marginTop*1+65))+'px' }"><scroll-view scroll-y="true" :style="{ height: (pageHeight-(marginTop*1+65))+'px' }"@scrolltolower="getBottom" :lower-threshold="80" :scroll-top="scrollTop"><view v-if="dataList.length>0" style="padding-bottom: 100rpx;"><view class="data_item" v-for="(item,index) in dataList" :key="index"@click="goDetail(item,index)"><view class="data_top"><image :src="getimg('originality_quote.png')" style="width: 64rpx;height: 64rpx;"></image><view class="data_content">{{item.idea_name}}</view><view class="lab_box" v-if="item.tag_list && item.tag_list.length>0"><view class="lab_item" v-for="(val,idx) in item.tag_list" :key="idx">{{val.tag_name}}</view></view><view class="times">{{item.updatetime | getDateDiff}}</view></view><view class="data_bot"><view class="share" @click.stop="goShare(item,index)"><image :src="getimg('share_gray.png')" style="width: 36rpx;height: 36rpx;"></image><view class="share_tt">分享</view></view><view class="infos"><view class="comm"><image :src="getimg('review_gray.png')" style="width: 44rpx;height: 44rpx;"></image><view class="comm_num">{{item.comment_count}}</view></view><view class="comm" @click.stop="addLike(item,index)"><image :src="item.is_like?getimg('like_red.png'):getimg('like_gray.png')"style="width: 44rpx;height: 44rpx;"></image><view class="comm_num">{{item.like_count}}</view></view></view></view></view></view><view v-else class="data_none" :style="'margin-top:'+(marginTop*1+150)+'px;'"><image :src="getimg('null-page.png')" style="width: 380rpx;height: 380rpx;"></image><view class="nothing">空空如也~</view></view></scroll-view></view>
如代码所以,我使用了touchstart,和touchend事件,并且加了:animation="animationData"
data(){return{scrollTop: 0,startX: 0,startY: 0,animationData: {}, // 动画}}
onLoad中需要先创建动画实例
onLoad() {uni.getSystemInfo({success: res => {this.pageHeight = res.windowHeight;}})// #ifdef MP-WEIXINconst systemInfo = wx.getSystemInfoSync();const res = wx.getMenuButtonBoundingClientRect();this.height = (res.top - systemInfo.statusBarHeight) * 2 + res.heightthis.marginTop = this.height + systemInfo.statusBarHeight// #endif// 创建动画实例this.animation = uni.createAnimation({timingFunction: 'ease',duration: 120})},
touchend结束事件中计算手指滑动距离,判断滑动方向并重新调用接口加载数据,并且在判断完滑动方向之后加动效,不让左右滑动看起来生硬
touchStart(event) {this.startX = event.touches[0].pageX;this.startY = event.touches[0].pageY;},touchEnd(event) {let deltaX = event.changedTouches[0].pageX - this.startX; let deltaY = event.changedTouches[0].pageY - this.startY;if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX)>60) {if (deltaX < 0) { //往左if (this.actTab == this.tabsList.length - 1) {this.actTab = 0} else {this.actTab = this.actTab * 1 + 1}this.cate_id = this.tabsList[this.actTab].id// 动画:左出右进this.animation.translateX('-100%').step().opacity(0).step({duration: 10}).translateX('100%').step({duration: 10}).translateX(0).opacity(1).step()this.animationData = this.animation.export()setTimeout(() => {this.animationData = {}}, 250)this.dataList = []this.page = 1this.getData()this.goJust() //scrollTop改为0} else if (deltaX > 0) { //往右if (this.actTab == 0) {this.actTab = this.tabsList.length - 1} else {this.actTab = this.actTab * 1 - 1}this.cate_id = this.tabsList[this.actTab].id// 动画:右出左进this.animation.translateX('100%').step() //先横向向右移至100%,即整块移没.opacity(0).step({ //再使滑块部分透明duration: 10}).translateX('-100%').step({ //然后趁透明横向向左移至-100%duration: 10}).translateX(0).opacity(1).step() //接着横向向右移动至初始位置并恢复透明度this.animationData = this.animation.export()// 为避免uniapp动画只有第一次生效,必须延迟删除动画实例数据setTimeout(() => {this.animationData = {}}, 250)this.dataList = []this.page = 1this.getData()this.goJust() //scrollTop改为0} else { // 挪动距离0}}else{}},
最后一步,因为内容包裹在scroll-view里,所以触底加载下一页写在scroll-view的触底事件里@scrolltolower="getBottom"
getBottom() {if (this.page < this.last_page) {this.page += 1this.getData()}},