|
|
<template> <view class="lending-container"> <view class="tab-sticky"> <my-tabs :tabData="tabData" :defaultIndex="currentIndex" :config="{ textColor: '#333' }" @tabClick="tabClick" /> </view>
<swiper class="swiper" :current="currentIndex" :style="{ height: currentSwiperHeight + 'px' }" @animationfinish="onSwiperEnd" @change="onSwiperChange" > <swiper-item v-for="(tabItem, idx) in tabData" :key="idx"> <view class="list-wrapper"> <uni-load-more status="loading" v-if="loadingMap[tabItem.status]" /> <view class="empty" v-else-if="!listData[tabItem.status] || listData[tabItem.status].length === 0"> 暂无{{ tabItem.label }}记录 </view> <block v-else> <book-list-item :class="'list-item-' + tabItem.status" v-for="(item, index) in listData[tabItem.status]" :key="index" :data="item" :ranking="index + 1" @click="goToDetail(item)" /> </block> </view> </swiper-item> </swiper> </view></template>
<script>import myTabs from "@/components/my-tabs/my-tabs.vue";import bookListItem from "@/components/book-list-item/book-list-item.vue";
export default { components: { myTabs, bookListItem }, data() { return { tabData: [ { label: "全部", status: "all", apiStatus: -1 }, { label: "在借中", status: "lending", apiStatus: 0 }, { label: "将过期", status: "expiring", apiStatus: 1 }, { label: "已过期", status: "expired", apiStatus: 2 }, ], currentIndex: 0, listData: {}, loadingMap: {}, swiperHeightData: {}, currentSwiperHeight: 400, currentPageScrollTop: 0 }; },
onLoad() { // 初始化数据结构
this.initDataStructure(); // 加载第一个tab的数据
const firstTab = this.getCurrentTab(); if (firstTab) { this.getListData(firstTab.status); } },
onPageScroll(res) { this.currentPageScrollTop = res.scrollTop; },
methods: { // 初始化数据结构
initDataStructure() { this.tabData.forEach(tab => { const key = tab.status; this.$set(this.listData, key, []); this.$set(this.loadingMap, key, true); }); }, // 获取当前选中的tab对象
getCurrentTab() { return this.tabData[this.currentIndex]; }, // 获取列表数据
async getListData(statusKey) { // 避免重复请求
if (this.listData[statusKey]?.length > 0) return; this.loadingMap[statusKey] = true; // 找到对应的tab配置
const tabConfig = this.tabData.find(tab => tab.status === statusKey); const apiStatus = tabConfig?.apiStatus ?? 0; // 调用API
const data = await this.fetchBorrowList(apiStatus); this.listData[statusKey] = data; this.loadingMap[statusKey] = false; // 计算高度
this.$nextTick(() => { this.calcSwiperHeight(statusKey); }); }, // API请求(可独立到 api 文件)
async fetchBorrowList(apiStatus) { // 模拟接口请求
return new Promise((resolve) => { setTimeout(() => { resolve(this.getMockData(apiStatus)); }, 600); }); }, // Mock数据(模拟后端返回)
getMockData(apiStatus) { const baseList = [ { imgCover: "https://qiniu.aiyxlib.com/1606124577077", title: "名侦探柯南", nickname: "青山刚昌", publish: "长春出版社", isbn: "1001" }, { imgCover: "https://qiniu.aiyxlib.com/1606124577077", title: "三体", nickname: "刘慈欣", publish: "重庆出版社", isbn: "1002" } ]; // 根据状态返回不同数据
switch(apiStatus) { case 0: return baseList; case 1: return [baseList[0]]; case 2: return []; case -1: return baseList; default: return []; } }, // 计算swiper高度
calcSwiperHeight(statusKey) { const selector = `.list-item-${statusKey}`; const query = uni.createSelectorQuery().in(this); query.selectAll(selector).boundingClientRect((res) => { let totalHeight = 200; // 默认高度
if (res && res.length) { totalHeight = res.reduce((sum, item) => sum + item.height + 8, 0); } this.swiperHeightData[statusKey] = totalHeight; this.currentSwiperHeight = totalHeight; }).exec(); }, // tab点击事件
tabClick(index) { this.currentIndex = index; const currentTab = this.getCurrentTab(); // 滚动到顶部
if (this.currentPageScrollTop > 100) { uni.pageScrollTo({ scrollTop: 100, duration: 100 }); } // 按需加载数据
const statusKey = currentTab.status; if (!this.listData[statusKey] || this.listData[statusKey].length === 0) { this.getListData(statusKey); } else { this.currentSwiperHeight = this.swiperHeightData[statusKey] || 400; } }, onSwiperChange(e) { if (e.detail.source === "touch") { this.currentIndex = e.detail.current; } }, onSwiperEnd() { const currentTab = this.getCurrentTab(); const statusKey = currentTab.status; if (!this.listData[statusKey] || this.listData[statusKey].length === 0) { this.getListData(statusKey); } else { this.currentSwiperHeight = this.swiperHeightData[statusKey] || 400; } }, goToDetail(item) { uni.navigateTo({ url: `/subpkg/pages/book-detail/book-detail?isbn=${item.isbn}` }); } }};</script><style lang="scss" scoped>.lending-container { background-color: #f5f5f5; min-height: 100vh;
.tab-sticky { position: sticky; top: 0; z-index: 99; background: #fff; }
.swiper { width: 100%; min-height: 300px; }
.swiper-item { width: 100%; height: 100%; }
.list-wrapper { padding: 10px; box-sizing: border-box; }
.empty { text-align: center; padding: 100px 0; color: #999; font-size: 14px; }}</style>
|