refactor: 迁移所有剩余页面到 LoadMoreList 组件
- message 页面:添加下拉刷新功能 - product-center 页面:保留搜索、tabs、计划书弹窗 - material-list 页面:保留分类缓存、搜索防抖 - search 页面:保留双列表、自动 tab 切换、三种状态 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Showing
4 changed files
with
155 additions
and
75 deletions
This diff is collapsed. Click to expand it.
| 1 | +<!-- | ||
| 2 | + * @Date: 2026-02-08 | ||
| 3 | + * @Description: 我的消息页 - 使用 LoadMoreList 组件重构版本 | ||
| 4 | +--> | ||
| 1 | <template> | 5 | <template> |
| 2 | - <view class="min-h-screen bg-[#F9FAFB] pb-safe"> | 6 | + <LoadMoreList |
| 7 | + :list="currentList" | ||
| 8 | + :page="currentPage" | ||
| 9 | + :page-size="pageSize" | ||
| 10 | + :has-more="hasMore" | ||
| 11 | + :loading="loading" | ||
| 12 | + :loading-more="loadingMore" | ||
| 13 | + :enable-pull-down-refresh="true" | ||
| 14 | + key-field="id" | ||
| 15 | + @load-more="handleLoadMore" | ||
| 16 | + @refresh="handleRefresh" | ||
| 17 | + > | ||
| 18 | + <!-- 头部 --> | ||
| 19 | + <template #header> | ||
| 3 | <NavHeader title="我的消息" /> | 20 | <NavHeader title="我的消息" /> |
| 21 | + </template> | ||
| 4 | 22 | ||
| 5 | - <!-- 列表区域 --> | 23 | + <!-- 列表项 --> |
| 6 | - <view class="p-4"> | 24 | + <template #item="{ item }"> |
| 7 | - <template v-if="messageList.length > 0"> | ||
| 8 | <view | 25 | <view |
| 9 | - v-for="item in messageList" | 26 | + class="message-item bg-white rounded-xl p-4 mb-3 shadow-sm active:opacity-70 transition-opacity" |
| 10 | - :key="item.id" | ||
| 11 | - class="bg-white rounded-xl p-4 mb-3 shadow-sm active:opacity-70 transition-opacity" | ||
| 12 | @tap="handleItemClick(item)" | 27 | @tap="handleItemClick(item)" |
| 13 | > | 28 | > |
| 14 | <view class="flex justify-between items-start mb-2"> | 29 | <view class="flex justify-between items-start mb-2"> |
| ... | @@ -26,29 +41,20 @@ | ... | @@ -26,29 +41,20 @@ |
| 26 | {{ item.intro || item.content || '暂无简介' }} | 41 | {{ item.intro || item.content || '暂无简介' }} |
| 27 | </view> | 42 | </view> |
| 28 | </view> | 43 | </view> |
| 29 | - | ||
| 30 | - <!-- 加载更多/没有更多 --> | ||
| 31 | - <view class="py-4 text-center text-[24rpx] text-gray-400"> | ||
| 32 | - <text v-if="loading">加载中...</text> | ||
| 33 | - <text v-else-if="!hasMore">没有更多了</text> | ||
| 34 | - <text v-else>上拉加载更多</text> | ||
| 35 | - </view> | ||
| 36 | </template> | 44 | </template> |
| 37 | 45 | ||
| 38 | <!-- 空状态 --> | 46 | <!-- 空状态 --> |
| 39 | - <nut-empty | 47 | + <template #empty> |
| 40 | - v-else-if="!loading && messageList.length === 0" | 48 | + <nut-empty description="暂无消息" image="empty" /> |
| 41 | - description="暂无消息" | 49 | + </template> |
| 42 | - image="empty" | 50 | + </LoadMoreList> |
| 43 | - /> | ||
| 44 | - </view> | ||
| 45 | - </view> | ||
| 46 | </template> | 51 | </template> |
| 47 | 52 | ||
| 48 | <script setup> | 53 | <script setup> |
| 49 | import { ref } from 'vue' | 54 | import { ref } from 'vue' |
| 50 | -import { useLoad, usePullDownRefresh, useReachBottom, stopPullDownRefresh } from '@tarojs/taro' | 55 | +import { useLoad } from '@tarojs/taro' |
| 51 | import { useGo } from '@/hooks/useGo' | 56 | import { useGo } from '@/hooks/useGo' |
| 57 | +import LoadMoreList from '@/components/LoadMoreList' | ||
| 52 | import NavHeader from '@/components/NavHeader.vue' | 58 | import NavHeader from '@/components/NavHeader.vue' |
| 53 | import { myListAPI } from '@/api/news' | 59 | import { myListAPI } from '@/api/news' |
| 54 | import { mockMessageListAPI } from '@/utils/mockData' | 60 | import { mockMessageListAPI } from '@/utils/mockData' |
| ... | @@ -58,91 +64,165 @@ const USE_MOCK_DATA = process.env.NODE_ENV === 'development' | ... | @@ -58,91 +64,165 @@ const USE_MOCK_DATA = process.env.NODE_ENV === 'development' |
| 58 | 64 | ||
| 59 | const go = useGo() | 65 | const go = useGo() |
| 60 | 66 | ||
| 61 | -const messageList = ref([]) | 67 | +/** |
| 62 | -const page = ref(1) | 68 | + * 当前列表数据 |
| 63 | -const limit = ref(10) | 69 | + * @type {Ref<Array<any>>} |
| 70 | + */ | ||
| 71 | +const currentList = ref([]) | ||
| 72 | + | ||
| 73 | +/** | ||
| 74 | + * 当前页码(从1开始) | ||
| 75 | + * @type {Ref<number>} | ||
| 76 | + */ | ||
| 77 | +const currentPage = ref(1) | ||
| 78 | + | ||
| 79 | +/** | ||
| 80 | + * 每页数量 | ||
| 81 | + * @type {number} | ||
| 82 | + */ | ||
| 83 | +const pageSize = 10 | ||
| 84 | + | ||
| 85 | +/** | ||
| 86 | + * 是否还有更多数据 | ||
| 87 | + * @type {Ref<boolean>} | ||
| 88 | + */ | ||
| 64 | const hasMore = ref(true) | 89 | const hasMore = ref(true) |
| 65 | -const loading = ref(false) | ||
| 66 | 90 | ||
| 67 | /** | 91 | /** |
| 68 | - * @description 加载消息列表 | 92 | + * 首次加载状态 |
| 69 | - * @param {boolean} refresh 是否刷新 | 93 | + * @type {Ref<boolean>} |
| 70 | */ | 94 | */ |
| 71 | -const fetchMessageList = async (refresh = false) => { | 95 | +const loading = ref(false) |
| 72 | - if (loading.value) return | ||
| 73 | 96 | ||
| 74 | - if (refresh) { | 97 | +/** |
| 75 | - page.value = 1 | 98 | + * 加载更多状态 |
| 76 | - hasMore.value = true | 99 | + * @type {Ref<boolean>} |
| 77 | - } else if (!hasMore.value) { | 100 | + */ |
| 78 | - return | 101 | +const loadingMore = ref(false) |
| 79 | - } | ||
| 80 | 102 | ||
| 103 | +/** | ||
| 104 | + * 获取消息列表 | ||
| 105 | + * | ||
| 106 | + * @param {Object} params - 请求参数 | ||
| 107 | + * @param {number} params.page - 页码(从1开始) | ||
| 108 | + * @param {number} params.limit - 每页数量 | ||
| 109 | + * @param {boolean} isLoadMore - 是否为加载更多 | ||
| 110 | + * @returns {Promise<void>} | ||
| 111 | + */ | ||
| 112 | +const fetchMessageList = async (params = {}, isLoadMore = false) => { | ||
| 113 | + try { | ||
| 114 | + // 如果是加载更多,使用 loadingMore 状态,否则使用 loading 状态 | ||
| 115 | + if (isLoadMore) { | ||
| 116 | + loadingMore.value = true | ||
| 117 | + } else { | ||
| 81 | loading.value = true | 118 | loading.value = true |
| 119 | + } | ||
| 82 | 120 | ||
| 83 | - try { | 121 | + console.log('[Message] 请求参数:', params) |
| 84 | console.log('[Message] 使用 Mock 数据:', USE_MOCK_DATA) | 122 | console.log('[Message] 使用 Mock 数据:', USE_MOCK_DATA) |
| 85 | 123 | ||
| 86 | // 根据开关选择使用真实 API 或 Mock 数据 | 124 | // 根据开关选择使用真实 API 或 Mock 数据 |
| 87 | const res = USE_MOCK_DATA | 125 | const res = USE_MOCK_DATA |
| 88 | - ? await mockMessageListAPI({ | 126 | + ? await mockMessageListAPI(params) |
| 89 | - page: page.value, | 127 | + : await myListAPI(params) |
| 90 | - limit: limit.value | 128 | + |
| 91 | - }) | 129 | + if (res.code === 1 && res.data) { |
| 92 | - : await myListAPI({ | 130 | + console.log('[Message] 数据:', res.data) |
| 93 | - page: page.value, | 131 | + |
| 94 | - limit: limit.value | 132 | + // 处理列表数据 |
| 95 | - }) | 133 | + if (res.data.list?.length) { |
| 96 | - | 134 | + const listData = res.data.list |
| 97 | - if (res.code === 1) { | 135 | + |
| 98 | - const list = res.data?.list || [] | 136 | + if (isLoadMore) { |
| 99 | - | 137 | + // 加载更多:追加数据 |
| 100 | - if (refresh) { | 138 | + currentList.value = [...currentList.value, ...listData] |
| 101 | - messageList.value = list | ||
| 102 | } else { | 139 | } else { |
| 103 | - messageList.value = [...messageList.value, ...list] | 140 | + // 首次加载或刷新:替换数据 |
| 141 | + currentList.value = listData | ||
| 104 | } | 142 | } |
| 105 | 143 | ||
| 106 | - if (list.length < limit.value) { | 144 | + // 判断是否还有更多数据 |
| 145 | + // 如果返回的数据量少于请求的量,说明没有更多了 | ||
| 146 | + hasMore.value = listData.length >= params.limit | ||
| 147 | + } else { | ||
| 148 | + // 没有数据了 | ||
| 149 | + if (isLoadMore) { | ||
| 107 | hasMore.value = false | 150 | hasMore.value = false |
| 108 | } else { | 151 | } else { |
| 109 | - page.value++ | 152 | + currentList.value = [] |
| 153 | + } | ||
| 110 | } | 154 | } |
| 155 | + } else { | ||
| 156 | + console.error('[Message] API 返回错误:', res.msg) | ||
| 111 | } | 157 | } |
| 112 | - } catch (err) { | 158 | + } catch (error) { |
| 113 | - console.error('获取消息列表失败:', err) | 159 | + console.error('[Message] 获取消息列表失败:', error) |
| 114 | } finally { | 160 | } finally { |
| 161 | + if (isLoadMore) { | ||
| 162 | + loadingMore.value = false | ||
| 163 | + } else { | ||
| 115 | loading.value = false | 164 | loading.value = false |
| 116 | - if (refresh) { | ||
| 117 | - stopPullDownRefresh() | ||
| 118 | } | 165 | } |
| 119 | } | 166 | } |
| 120 | } | 167 | } |
| 121 | 168 | ||
| 122 | /** | 169 | /** |
| 123 | - * @description 跳转到详情页 | 170 | + * 页面加载时获取数据 |
| 124 | - * @param {Object} item 消息对象 | ||
| 125 | */ | 171 | */ |
| 126 | -const handleItemClick = (item) => { | 172 | +useLoad(async (options) => { |
| 127 | - go('/pages/message-detail/index', { id: item.id }) | 173 | + console.log('[Message] 页面参数:', options) |
| 128 | -} | ||
| 129 | 174 | ||
| 130 | -// 页面加载 | 175 | + // 重置分页状态 |
| 131 | -useLoad(() => { | 176 | + currentPage.value = 1 |
| 132 | - fetchMessageList(true) | 177 | + hasMore.value = true |
| 133 | -}) | ||
| 134 | 178 | ||
| 135 | -// 下拉刷新 | 179 | + // 获取消息列表 |
| 136 | -usePullDownRefresh(() => { | 180 | + await fetchMessageList({ page: 1, limit: pageSize }) |
| 137 | - fetchMessageList(true) | ||
| 138 | }) | 181 | }) |
| 139 | 182 | ||
| 140 | -// 上拉加载更多 | 183 | +/** |
| 141 | -useReachBottom(() => { | 184 | + * 处理加载更多事件 |
| 142 | - fetchMessageList() | 185 | + * |
| 143 | -}) | 186 | + * @param {number} page - 下一页页码 |
| 187 | + * @returns {Promise<void>} | ||
| 188 | + */ | ||
| 189 | +const handleLoadMore = async (page) => { | ||
| 190 | + console.log('[Message] 加载更多,页码:', page) | ||
| 191 | + | ||
| 192 | + // 更新页码 | ||
| 193 | + currentPage.value = page | ||
| 194 | + | ||
| 195 | + // 加载下一页数据 | ||
| 196 | + await fetchMessageList( | ||
| 197 | + { page: page, limit: pageSize }, | ||
| 198 | + true // 标记为加载更多 | ||
| 199 | + ) | ||
| 200 | +} | ||
| 201 | + | ||
| 202 | +/** | ||
| 203 | + * 处理下拉刷新事件 | ||
| 204 | + */ | ||
| 205 | +const handleRefresh = async () => { | ||
| 206 | + console.log('[Message] 下拉刷新') | ||
| 207 | + | ||
| 208 | + // 重置分页状态 | ||
| 209 | + currentPage.value = 1 | ||
| 210 | + hasMore.value = true | ||
| 211 | + | ||
| 212 | + // 刷新数据 | ||
| 213 | + await fetchMessageList({ page: 1, limit: pageSize }) | ||
| 214 | +} | ||
| 215 | + | ||
| 216 | +/** | ||
| 217 | + * 跳转到详情页 | ||
| 218 | + * | ||
| 219 | + * @param {Object} item - 消息对象 | ||
| 220 | + */ | ||
| 221 | +const handleItemClick = (item) => { | ||
| 222 | + go('/pages/message-detail/index', { id: item.id }) | ||
| 223 | +} | ||
| 144 | </script> | 224 | </script> |
| 145 | 225 | ||
| 146 | <style lang="less"> | 226 | <style lang="less"> |
| 147 | -/* Scoped styles if needed */ | 227 | +/* LoadMoreList 组件已内置样式,此处无需额外样式 */ |
| 148 | </style> | 228 | </style> | ... | ... |
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
-
Please register or login to post a comment