当前位置:   article > 正文

uniapp-微信小程序实现swiper左右滚动切换tab,上下滚动加载列表_微信小程序swipe和tab

微信小程序swipe和tab

思路:左右滑动使用swiper,上下滑动用scroll-view,swiper改变时同时改变tab并更新列表

坑点:

1. swiper高度问题,导致滑动不到最底部和最顶部

        需要手动计算,减去顶部高度和底部tabbar,并且需要同时设置padding-top和paddin-botton,否则列表显示不完整

2. 由于最开始的代码是每次切换tab后都会重新请求,导致swiper还没切换成功的过程中,显示的列表错误

        将代码改造成每一个tab下面的list都是隔离开的,原先使用了一个list维护不同tab

3. 每个tab下的list的加载完成状态也需要隔离开,否则导致tab1切换到tab2以后,tab2将控制加载完成的状态改为true后,返回tab1无法加载第2页了

4. 触底加载

        无法使用系统的触底加载了,需要使用scroll-view的自定义上拉刷新方法

5. 下拉更新

        也需要自定义,由于目前我的系统自带的还是正常的,所以还没有改造,但是体验没有scroll-view的好,因为顶部tab会遮挡下拉刷新的loading状态,后期再改造

源码:已去除不相关代码

  1. <template>
  2. <view class="home-page">
  3. <my-tabs :tabs="tabs" :currentTab="currentTabIndex" @change="onTabChange" :top="topStyle.total" isFixed>
  4. </my-tabs>
  5. <swiper class="activity-swiper" :current="currentTabIndex" interval="500" @change="onSwiperChange"
  6. :style="{ height: `calc(100vh - ${listStyle.paddingTop} - ${listStyle.paddingBottom})`, paddingBottom: listStyle.paddingBottom, paddingTop: listStyle.paddingTop,}">
  7. <swiper-item class="activity-swiper-item" v-for="item in tabs" :key="item.key" :item-id="item.key"
  8. :style="{ paddingBottom: 0, paddingTop: 0 }">
  9. <scroll-view scroll-y class="scroll-list" @scrolltolower="onBottom" :style="{ height: '100%' }"
  10. :scroll-top="scrollTop" @scroll="scroll">
  11. <card-activity v-for="(activity, index) in listData[item.index]" :key="activity.activityId" :data="activity"
  12. custom-class="activity-item" @click="toActivityDetail" @share="onShare"></card-activity>
  13. <tui-nomore v-if="isListFinished[item.index] && listData[item.index].length > 3"></tui-nomore>
  14. </scroll-view>
  15. </swiper-item>
  16. </swiper>
  17. </view>
  18. </template>
  19. <script>
  20. import {
  21. mapState
  22. } from 'vuex'
  23. import {
  24. userApi,
  25. activityApi
  26. } from '@/api'
  27. import {
  28. defaultConst,
  29. shareTypeConst,
  30. } from '@/const'
  31. const tabObj = {
  32. textList: [{
  33. name: '我创建的',
  34. key: 'create',
  35. index: 0
  36. },
  37. {
  38. name: '我参与的',
  39. key: 'partake',
  40. index: 1
  41. },
  42. {
  43. name: '我关注的',
  44. key: 'follow',
  45. index: 2
  46. }
  47. ],
  48. value: {
  49. 0: 1,
  50. 1: 2,
  51. 2: 3,
  52. }
  53. }
  54. export default {
  55. data() {
  56. return {
  57. currentActivity: {},
  58. tabs: tabObj.textList,
  59. currentTabIndex: 0,
  60. currentTabValue: 1,
  61. listData: {
  62. 0: [], // create
  63. 1: [], // partake
  64. 2: [], // follow
  65. },
  66. // 每个tab的加载状态隔离开:解决切换到第三个tab加载完成后,返回第一个tab无法加载第二页的问题
  67. isListFinished: [false, false, false],
  68. pageIndex: 1,
  69. isListLoading: false,
  70. tabbarIndex: 0,
  71. scrollTop: 0,
  72. oldScrollTop: 0
  73. }
  74. },
  75. computed: {
  76. ...mapState(['systemInfo', 'userInfo', 'showTabBarDot']),
  77. topStyle() {
  78. const {
  79. statusBarHeight
  80. } = this.systemInfo
  81. const menuButtonInfo = wx.getMenuButtonBoundingClientRect()
  82. const navigationBarHeight = (menuButtonInfo.top - statusBarHeight) * 2 + menuButtonInfo.height
  83. return {
  84. statusBarHeight,
  85. navigationBarHeight,
  86. total: statusBarHeight + navigationBarHeight
  87. }
  88. },
  89. listStyle() {
  90. return {
  91. paddingTop: this.topStyle.total + 45 + 'px',
  92. paddingBottom: '180rpx',
  93. }
  94. }
  95. },
  96. watch: {
  97. currentTabIndex(value) {
  98. // 首次切换tab才会重新加载数据
  99. if (!this.listData[value].length) this.getActivityList(true)
  100. // this.isListFinished = false
  101. },
  102. },
  103. methods: {
  104. async getActivityList(isRefresh, params, isFirst) {
  105. const tab = this.currentTabIndex
  106. this.showNoData = false
  107. if (isRefresh) {
  108. this.pageIndex = defaultConst.DEFAULT_PAGE_INDEX
  109. this.isListFinished[this.currentTabIndex] = false
  110. this.listData[this.currentTabIndex] = []
  111. }
  112. const data = {
  113. pageIndex: this.pageIndex++,
  114. pageSize: defaultConst.DEFAULT_PAGE_SIZE,
  115. type: this.currentTabValue,
  116. }
  117. Object.keys(params || {}).map(key => {
  118. if (params[key]) {
  119. data[key] = params[key]
  120. }
  121. })
  122. const {
  123. hasNext,
  124. list
  125. } = await activityApi.getList(data)
  126. if (tab !== this.currentTabIndex) return
  127. if (!hasNext) {
  128. this.isListFinished[this.currentTabIndex] = true
  129. }
  130. if (isRefresh) {
  131. uni.stopPullDownRefresh()
  132. }
  133. this.listData[this.currentTabIndex].push(...list)
  134. },
  135. onTabChange({
  136. index
  137. }) {
  138. this.currentTabIndex = index
  139. this.currentTabValue = tabObj.value[index]
  140. if (!this.listData[index].length) this.skeletonShow = true
  141. this.goTop()
  142. },
  143. onSwiperChange(e) {
  144. this.currentTabIndex = e.detail.current
  145. this.currentTabValue = tabObj.value[e.detail.current]
  146. if (!this.listData[e.detail.current].length) this.skeletonShow = true
  147. this.goTop()
  148. },
  149. onNoticeClose() {
  150. this.showNotice = false;
  151. },
  152. toActivityDetail(id) {
  153. uni.navigateTo({
  154. url: `/pages/activity/detail?activityId=${id}`
  155. })
  156. },
  157. async onShare(activity) {
  158. const res = await activityApi.getDetail({
  159. activityId: activity.activityId
  160. })
  161. this.currentActivity = res
  162. this.$refs.shareActivity.share()
  163. },
  164. toCreate() {
  165. uni.navigateTo({
  166. url: '/pages/activity/create'
  167. })
  168. },
  169. onBottom() {
  170. console.log('触底了')
  171. if (!this.isListFinished[this.currentTabIndex]) {
  172. this.getActivityList(false)
  173. }
  174. },
  175. scroll(e) {
  176. //记录scroll 位置
  177. this.oldScrollTop = e.detail.scrollTop
  178. },
  179. goTop(e) {
  180. //视图会发生重新渲染 scrollTop不会随着滚动而实时更新 所以需要手动设置 之所以不在scroll方法中设置是为了防止页面抖动
  181. this.scrollTop = this.oldScrollTop
  182. //当视图渲染结束 重新设置为0
  183. wx.nextTick(() => {
  184. this.scrollTop = 0
  185. });
  186. }
  187. },
  188. onLoad() {
  189. this.skeletonShow = true
  190. this.getActivityList(false)
  191. },
  192. onPullDownRefresh() {
  193. this.skeletonShow = true
  194. this.getActivityList(true)
  195. },
  196. }
  197. </script>
  198. <style lang="scss" scoped>
  199. .activity-swiper {
  200. &-item {
  201. box-sizing: border-box;
  202. padding-left: 20rpx;
  203. padding-right: 20rpx;
  204. }
  205. /deep/ .activity-item {
  206. margin-top: 20rpx;
  207. }
  208. }
  209. .text-link {
  210. color: $text-link;
  211. }
  212. .list-no-data-text {
  213. color: $text-3;
  214. }
  215. </style>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/39833
推荐阅读
  

闽ICP备14008679号