图书馆小程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

224 lines
5.0 KiB

2 weeks ago
  1. <template>
  2. <view class="lending-container">
  3. <!-- Tabs 吸顶 -->
  4. <view class="tab-sticky">
  5. <my-tabs
  6. :tabData="tabData"
  7. :defaultIndex="currentIndex"
  8. :config="{ textColor: '#333' }"
  9. @tabClick="tabClick"
  10. />
  11. </view>
  12. <!-- Swiper 内容区 -->
  13. <swiper
  14. class="swiper"
  15. :current="currentIndex"
  16. :style="{ height: currentSwiperHeight + 'px' }"
  17. @animationfinish="onSwiperEnd"
  18. @change="onSwiperChange"
  19. duration="300"
  20. >
  21. <swiper-item class="swiper-item" v-for="(tabItem, tabIndex) in tabData" :key="tabIndex">
  22. <view class="list-wrapper">
  23. <!-- 加载中 -->
  24. <uni-load-more status="loading" v-if="loadingMap[tabIndex]" />
  25. <!-- 空数据 -->
  26. <view class="empty" v-else-if="!listData[tabIndex] || listData[tabIndex].length === 0">
  27. 暂无借阅记录
  28. </view>
  29. <!-- 图书列表 -->
  30. <block v-else>
  31. <book-list-item
  32. :class="'list-item-' + tabIndex"
  33. v-for="(item, index) in listData[tabIndex]"
  34. :key="index"
  35. :data="item"
  36. :ranking="index + 1"
  37. @click="goToDetail(item)"
  38. />
  39. </block>
  40. </view>
  41. </swiper-item>
  42. </swiper>
  43. </view>
  44. </template>
  45. <script>
  46. import myTabs from "@/components/my-tabs/my-tabs.vue";
  47. import bookListItem from "@/components/book-list-item/book-list-item.vue";
  48. export default {
  49. components: {
  50. myTabs,
  51. bookListItem
  52. },
  53. data() {
  54. return {
  55. tabData: [
  56. { label: "在借中" },
  57. { label: "将过期" },
  58. { label: "已过期" }
  59. ],
  60. currentIndex: 0,
  61. // 列表数据缓存
  62. listData: {
  63. 0: [],
  64. 1: [],
  65. 2: []
  66. },
  67. // 每个页面的加载状态
  68. loadingMap: {
  69. 0: true,
  70. 1: true,
  71. 2: true
  72. },
  73. // Swiper 高度自适应
  74. currentSwiperHeight: 400,
  75. swiperHeightData: {},
  76. // 页面滚动
  77. currentPageScrollTop: 0
  78. };
  79. },
  80. onLoad() {
  81. this.getListData(0);
  82. },
  83. onPageScroll(res) {
  84. this.currentPageScrollTop = res.scrollTop;
  85. },
  86. methods: {
  87. async getListData(index) {
  88. this.loadingMap[index] = true;
  89. setTimeout(() => {
  90. const mockData = this.getMockListByStatus(index);
  91. this.listData[index] = mockData;
  92. this.loadingMap[index] = false;
  93. this.$nextTick(() => {
  94. this.calcSwiperHeight(index);
  95. });
  96. }, 600);
  97. },
  98. getMockListByStatus(status) {
  99. const baseList = [
  100. {
  101. imgCover: "https://qiniu.aiyxlib.com/1606124577077",
  102. title: "名侦探柯南",
  103. nickname: "青山刚昌",
  104. publish: "长春出版社",
  105. isbn: "1001"
  106. },
  107. {
  108. imgCover: "https://qiniu.aiyxlib.com/1606124577077",
  109. title: "三体",
  110. nickname: "刘慈欣",
  111. publish: "重庆出版社",
  112. isbn: "1002"
  113. }
  114. ];
  115. if (status === 0) return baseList;
  116. if (status === 1) return [baseList[0]];
  117. if (status === 2) return [];
  118. return [];
  119. },
  120. calcSwiperHeight(index) {
  121. const query = uni.createSelectorQuery().in(this);
  122. query
  123. .selectAll(`.list-item-${index}`)
  124. .boundingClientRect((res) => {
  125. let totalHeight = 0;
  126. if (res && res.length) {
  127. res.forEach((item) => {
  128. totalHeight += item.height + 8;
  129. });
  130. } else {
  131. totalHeight = 200;
  132. }
  133. this.swiperHeightData[index] = totalHeight;
  134. this.currentSwiperHeight = totalHeight;
  135. })
  136. .exec();
  137. },
  138. tabClick(index) {
  139. this.currentIndex = index;
  140. if (this.currentPageScrollTop > 100) {
  141. uni.pageScrollTo({ scrollTop: 100, duration: 100 });
  142. }
  143. if (!this.listData[index] || this.listData[index].length === 0) {
  144. this.getListData(index);
  145. } else {
  146. this.currentSwiperHeight = this.swiperHeightData[index] || 400;
  147. }
  148. },
  149. onSwiperChange(e) {
  150. if (e.detail.source === "touch") {
  151. this.currentIndex = e.detail.current;
  152. }
  153. },
  154. onSwiperEnd() {
  155. const index = this.currentIndex;
  156. if (!this.listData[index] || this.listData[index].length === 0) {
  157. this.getListData(index);
  158. } else {
  159. this.currentSwiperHeight = this.swiperHeightData[index] || 400;
  160. }
  161. },
  162. goToDetail(item) {
  163. uni.navigateTo({
  164. url: "/subpkg/pages/book-detail/book-detail?isbn=" + item.isbn
  165. });
  166. }
  167. }
  168. };
  169. </script>
  170. <style lang="scss" scoped>
  171. .lending-container {
  172. background-color: #f5f5f5;
  173. min-height: 100vh;
  174. .tab-sticky {
  175. position: sticky;
  176. top: 0;
  177. z-index: 99;
  178. background: #fff;
  179. }
  180. .swiper {
  181. width: 100%;
  182. min-height: 300px;
  183. }
  184. .swiper-item {
  185. width: 100%;
  186. height: 100%;
  187. }
  188. .list-wrapper {
  189. padding: 10px;
  190. box-sizing: border-box;
  191. }
  192. .empty {
  193. text-align: center;
  194. padding: 100px 0;
  195. color: #999;
  196. font-size: 14px;
  197. }
  198. }
  199. </style>