公告列表采用分页组件

This commit is contained in:
WindowBird 2025-08-26 09:25:40 +08:00
parent 5e09db3d16
commit de2ac5d37c
3 changed files with 91 additions and 119 deletions

View File

@ -6,11 +6,11 @@
<view class="loading-spinner"></view> <view class="loading-spinner"></view>
<text class="loading-text">{{ loadingText }}</text> <text class="loading-text">{{ loadingText }}</text>
</view> </view>
<view v-else-if="noMore && list.length > 0" class="no-more-state"> <view v-else-if="noMore && list.length > 0" class="no-more-state">
<text class="no-more-text">{{ noMoreText }}</text> <text class="no-more-text">{{ noMoreText }}</text>
</view> </view>
<view v-else-if="list.length === 0 && !loading" class="empty-state"> <view v-else-if="list.length === 0 && !loading" class="empty-state">
<view class="empty-icon">{{ emptyIcon }}</view> <view class="empty-icon">{{ emptyIcon }}</view>
<text class="empty-text">{{ emptyText }}</text> <text class="empty-text">{{ emptyText }}</text>
@ -24,19 +24,19 @@
{{ total }} {{ currentPage }} / {{ totalPages }} {{ total }} {{ currentPage }} / {{ totalPages }}
</text> </text>
</view> </view>
<view class="pager-controls"> <view class="pager-controls">
<button <button
class="pager-btn prev-btn" class="pager-btn prev-btn"
:disabled="currentPage <= 1" :disabled="currentPage <= 1"
@click="handlePageChange(currentPage - 1)" @click="handlePageChange(currentPage - 1)"
> >
上一页 上一页
</button> </button>
<view class="page-numbers"> <view class="page-numbers">
<button <button
v-for="page in visiblePages" v-for="page in visiblePages"
:key="page" :key="page"
:class="['page-btn', { active: page === currentPage }]" :class="['page-btn', { active: page === currentPage }]"
@click="handlePageChange(page)" @click="handlePageChange(page)"
@ -44,9 +44,9 @@
{{ page }} {{ page }}
</button> </button>
</view> </view>
<button <button
class="pager-btn next-btn" class="pager-btn next-btn"
:disabled="currentPage >= totalPages" :disabled="currentPage >= totalPages"
@click="handlePageChange(currentPage + 1)" @click="handlePageChange(currentPage + 1)"
> >
@ -65,114 +65,114 @@ export default {
mode: { mode: {
type: String, type: String,
default: 'loadMore', default: 'loadMore',
validator: value => ['loadMore', 'pager'].includes(value) validator: value => ['loadMore', 'pager'].includes(value),
}, },
// //
list: { list: {
type: Array, type: Array,
default: () => [] default: () => [],
}, },
// //
total: { total: {
type: Number, type: Number,
default: 0 default: 0,
}, },
// //
currentPage: { currentPage: {
type: Number, type: Number,
default: 1 default: 1,
}, },
// //
pageSize: { pageSize: {
type: Number, type: Number,
default: 10 default: 10,
}, },
// //
loading: { loading: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
// //
noMore: { noMore: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
// //
loadingText: { loadingText: {
type: String, type: String,
default: '正在加载...' default: '正在加载...',
}, },
noMoreText: { noMoreText: {
type: String, type: String,
default: '没有更多数据了' default: '没有更多数据了',
}, },
emptyText: { emptyText: {
type: String, type: String,
default: '暂无数据' default: '暂无数据',
}, },
emptyIcon: { emptyIcon: {
type: String, type: String,
default: '📋' default: '📋',
}, },
// //
visiblePageCount: { visiblePageCount: {
type: Number, type: Number,
default: 5 default: 5,
} },
}, },
computed: { computed: {
// //
totalPages() { totalPages() {
return Math.ceil(this.total / this.pageSize) return Math.ceil(this.total / this.pageSize)
}, },
// //
visiblePages() { visiblePages() {
const pages = [] const pages = []
const half = Math.floor(this.visiblePageCount / 2) const half = Math.floor(this.visiblePageCount / 2)
let start = Math.max(1, this.currentPage - half) let start = Math.max(1, this.currentPage - half)
let end = Math.min(this.totalPages, start + this.visiblePageCount - 1) let end = Math.min(this.totalPages, start + this.visiblePageCount - 1)
// //
if (end - start + 1 < this.visiblePageCount) { if (end - start + 1 < this.visiblePageCount) {
start = Math.max(1, end - this.visiblePageCount + 1) start = Math.max(1, end - this.visiblePageCount + 1)
} }
for (let i = start; i <= end; i++) { for (let i = start; i <= end; i++) {
pages.push(i) pages.push(i)
} }
return pages return pages
} },
}, },
methods: { methods: {
// //
handlePageChange(page) { handlePageChange(page) {
if (page < 1 || page > this.totalPages || page === this.currentPage) { if (page < 1 || page > this.totalPages || page === this.currentPage) {
return return
} }
this.$emit('page-change', page) this.$emit('page-change', page)
}, },
// //
reset() { reset() {
this.$emit('reset') this.$emit('reset')
} },
} },
} }
</script> </script>
@ -192,7 +192,7 @@ export default {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 20rpx 0; padding: 20rpx 0;
.loading-spinner { .loading-spinner {
width: 40rpx; width: 40rpx;
height: 40rpx; height: 40rpx;
@ -202,7 +202,7 @@ export default {
animation: spin 1s linear infinite; animation: spin 1s linear infinite;
margin-right: 20rpx; margin-right: 20rpx;
} }
.loading-text { .loading-text {
font-size: 28rpx; font-size: 28rpx;
color: #666; color: #666;
@ -211,7 +211,7 @@ export default {
.no-more-state { .no-more-state {
padding: 20rpx 0; padding: 20rpx 0;
.no-more-text { .no-more-text {
font-size: 24rpx; font-size: 24rpx;
color: #999; color: #999;
@ -220,12 +220,12 @@ export default {
.empty-state { .empty-state {
padding: 40rpx 0; padding: 40rpx 0;
.empty-icon { .empty-icon {
font-size: 80rpx; font-size: 80rpx;
margin-bottom: 20rpx; margin-bottom: 20rpx;
} }
.empty-text { .empty-text {
font-size: 28rpx; font-size: 28rpx;
color: #999; color: #999;
@ -242,7 +242,7 @@ export default {
.pager-info { .pager-info {
text-align: center; text-align: center;
margin-bottom: 20rpx; margin-bottom: 20rpx;
.pager-text { .pager-text {
font-size: 24rpx; font-size: 24rpx;
color: #666; color: #666;
@ -264,13 +264,13 @@ export default {
background: #fff; background: #fff;
color: #333; color: #333;
font-size: 26rpx; font-size: 26rpx;
&:disabled { &:disabled {
color: #ccc; color: #ccc;
background: #f5f5f5; background: #f5f5f5;
border-color: #d9d9d9; border-color: #d9d9d9;
} }
&:not(:disabled):active { &:not(:disabled):active {
background: #f0f0f0; background: #f0f0f0;
} }
@ -289,20 +289,24 @@ export default {
background: #fff; background: #fff;
color: #333; color: #333;
font-size: 26rpx; font-size: 26rpx;
&.active { &.active {
background: #1890ff; background: #1890ff;
color: #fff; color: #fff;
border-color: #1890ff; border-color: #1890ff;
} }
&:not(.active):active { &:not(.active):active {
background: #f0f0f0; background: #f0f0f0;
} }
} }
@keyframes spin { @keyframes spin {
0% { transform: rotate(0deg); } 0% {
100% { transform: rotate(360deg); } transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
} }
</style> </style>

View File

@ -4,61 +4,33 @@
<uni-card :extra="item.createTime" :title="item.title" @click="detail(item)"></uni-card> <uni-card :extra="item.createTime" :title="item.title" @click="detail(item)"></uni-card>
</view> </view>
<!-- 加载更多状态 --> <!-- 分页组件 -->
<view v-if="noData && list.length > 0" class="load-more"> <pagination
<text class="no-more-text">没有更多数据了</text> :current-page="pagination.currentPage"
</view> :list="list"
:loading="loading"
:mode="'loadMore'"
:no-more="noMore"
:page-size="pagination.pageSize"
:total="pagination.total"
@page-change="handlePageChange"
/>
</view> </view>
</template> </template>
<script setup> <script setup>
import { ref, onMounted } from 'vue' import { onMounted } from 'vue'
import { getArticleList } from '@/api/article/article.js' import { getArticleList } from '@/api/article/article.js'
import { onUnload, onReachBottom } from '@dcloudio/uni-app' import { onReachBottom } from '@dcloudio/uni-app'
import { usePagination } from '@/composables/usePagination.js'
const list = ref([]) // 使
const noData = ref(false) const { list, loading, noMore, pagination, getList, loadMore } = usePagination({
const loading = ref(false) fetchData: getArticleList,
defaultParams: {},
//data mode: 'loadMore',
const queryParams = { pageSize: 9,
pageNum: 1, })
pageSize: 6,
}
//
const getList = async () => {
if (loading.value) return
try {
loading.value = true
let res = await getArticleList(queryParams)
// res.data
const newData = res?.rows || []
//
if (queryParams.pageNum === 1) {
list.value = newData
} else {
list.value = [...list.value, ...newData]
}
if (queryParams.pageNum * queryParams.pageSize >= res.total) {
noData.value = true
}
console.log('订单列表:', list.value)
} catch (error) {
console.error('获取订单列表失败:', error)
uni.showToast({
title: '获取订单列表失败',
icon: 'none',
})
} finally {
loading.value = false
}
}
const detail = item => { const detail = item => {
uni.navigateTo({ uni.navigateTo({
@ -71,18 +43,15 @@ onMounted(() => {
getList() getList()
}) })
onUnload(() => { //
// onReachBottom(() => {
list.value = [] loadMore()
noData.value = false
loading.value = false
}) })
onReachBottom(() => { //
if (noData.value || loading.value) return const handlePageChange = page => {
queryParams.pageNum++ console.log('页码变化:', page)
getList() }
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -73,7 +73,6 @@ import { onMounted } from 'vue'
import { onReachBottom } from '@dcloudio/uni-app' import { onReachBottom } from '@dcloudio/uni-app'
import { usePagination } from '@/composables/usePagination.js' import { usePagination } from '@/composables/usePagination.js'
import { getMyOrder } from '@/api/order/myOrder.js' import { getMyOrder } from '@/api/order/myOrder.js'
import Pagination from '@/components/pagination/pagination.vue'
// 使 // 使
const { list, loading, noMore, pagination, getList, loadMore } = usePagination({ const { list, loading, noMore, pagination, getList, loadMore } = usePagination({