infinite scrolling instead of pagination for home page

pull/369/head
ROC 1 year ago
parent f5f0d18e14
commit 02d5474086

@ -3,9 +3,8 @@
<div class="logo-wrap"> <div class="logo-wrap">
<n-image class="logo-img" width="36" :src="LOGO" :preview-disabled="true" @click="goHome" /> <n-image class="logo-img" width="36" :src="LOGO" :preview-disabled="true" @click="goHome" />
</div> </div>
<n-menu :accordion="true" :icon-size="24" <n-menu :accordion="true" :icon-size="24" :options="menuOptions" :render-label="renderMenuLabel"
:options="menuOptions" :render-label="renderMenuLabel" :render-icon="renderMenuIcon" :value="selectedPath" :render-icon="renderMenuIcon" :value="selectedPath" @update:value="goRouter" />
@update:value="goRouter" />
<div class="user-wrap" v-if="store.state.userInfo.id > 0"> <div class="user-wrap" v-if="store.state.userInfo.id > 0">
<n-avatar class="user-avatar" round :size="34" :src="store.state.userInfo.avatar" /> <n-avatar class="user-avatar" round :size="34" :src="store.state.userInfo.avatar" />
@ -135,7 +134,7 @@ const menuOptions = computed(() => {
}, },
]; ];
if (import.meta.env.VITE_ENABLE_ANOUNCEMENT.toLowerCase() === 'true') { if (import.meta.env.VITE_ENABLE_ANOUNCEMENT.toLowerCase() === 'true') {
options.push( { options.push({
label: '', label: '',
key: 'anouncement', key: 'anouncement',
icon: () => h(MegaphoneOutline), icon: () => h(MegaphoneOutline),
@ -234,7 +233,11 @@ const renderMenuIcon = (option: AnyObject) => {
const goRouter = (name: string, item: any = {}) => { const goRouter = (name: string, item: any = {}) => {
selectedPath.value = name; selectedPath.value = name;
router.push({ name }); router.push({
name, query: {
t: (new Date().getTime())
}
});
}; };
const goHome = () => { const goHome = () => {
if (route.path === '/') { if (route.path === '/') {
@ -339,7 +342,7 @@ window.$message = useMessage();
.login-only-wrap { .login-only-wrap {
display: flex; display: flex;
justify-content:center; justify-content: center;
width: 100%; width: 100%;
button { button {
@ -378,6 +381,7 @@ window.$message = useMessage();
} }
.user-wrap { .user-wrap {
.user-avatar, .user-avatar,
.user-info, .user-info,
.login-only-wrap, .login-only-wrap,
@ -385,9 +389,9 @@ window.$message = useMessage();
margin-bottom: 32px; margin-bottom: 32px;
} }
// .user-mini-wrap { // .user-mini-wrap {
// display: block !important; // display: block !important;
// } // }
} }
} }
</style> </style>

@ -8,10 +8,11 @@
<compose @post-success="onPostSuccess" /> <compose @post-success="onPostSuccess" />
</n-list-item> </n-list-item>
<div v-if="loading" class="skeleton-wrap"> <div v-if="loading && list.length === 0" class="skeleton-wrap">
<post-skeleton :num="pageSize" /> <post-skeleton :num="pageSize" />
</div> </div>
<div v-else>
<div>
<div class="empty-wrap" v-if="list.length === 0"> <div class="empty-wrap" v-if="list.length === 0">
<n-empty size="large" description="暂无数据" /> <n-empty size="large" description="暂无数据" />
</div> </div>
@ -28,14 +29,17 @@
</div> </div>
</n-list> </n-list>
<div class="pagination-wrap" v-if="totalPage > 0">
<n-pagination <n-space v-if="totalPage > 0" justify="center">
:page="page" <InfiniteLoading class="load-more" :slots="{ complete: '没有更多泡泡了', error: '加载出错' }" @infinite="nextPage()">
@update:page="updatePage" <template #spinner>
:page-slot="!store.state.collapsedRight ? 8 : 5" <div class="load-more-wrap">
:page-count="totalPage" <n-spin :size="14" v-if="!noMore" />
/> <span class="load-more-spinner">{{ noMore ? '' : '' }}</span>
</div> </div>
</template>
</InfiniteLoading>
</n-space>
</div> </div>
</template> </template>
@ -43,6 +47,7 @@
import { ref, onMounted, computed, watch } from 'vue'; import { ref, onMounted, computed, watch } from 'vue';
import { useStore } from 'vuex'; import { useStore } from 'vuex';
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import InfiniteLoading from "v3-infinite-loading";
import { getPosts } from '@/api/post'; import { getPosts } from '@/api/post';
const store = useStore(); const store = useStore();
@ -50,8 +55,9 @@ const route = useRoute();
const router = useRouter(); const router = useRouter();
const loading = ref(false); const loading = ref(false);
const noMore = ref(false);
const list = ref<any[]>([]); const list = ref<any[]>([]);
const page = ref(+(route.query.p as string) || 1); const page = ref(1);
const pageSize = ref(20); const pageSize = ref(20);
const totalPage = ref(0); const totalPage = ref(0);
const title = computed(() => { const title = computed(() => {
@ -78,10 +84,18 @@ const loadPosts = () => {
}) })
.then((rsp) => { .then((rsp) => {
loading.value = false; loading.value = false;
list.value = rsp.list; if (rsp.list.length === 0) {
totalPage.value = Math.ceil(rsp.pager.total_rows / pageSize.value); noMore.value = true
}
window.scrollTo(0, 0); if (page.value > 1) {
list.value = list.value.concat(rsp.list);
} else {
list.value = rsp.list;
window.scrollTo(0, 0);
}
totalPage.value = Math.ceil(rsp.pager.total_rows / pageSize.value);
}) })
.catch((err) => { .catch((err) => {
loading.value = false; loading.value = false;
@ -99,36 +113,31 @@ const onPostSuccess = (post: Item.PostProps) => {
}); });
return; return;
} }
// 如果实在第一页,就地插入新推文到文章列表中 // 如果实在第一页,就地插入新推文到文章列表中
let items = []; let items = [];
let length = list.value.length; let length = list.value.length;
if (length == pageSize.value) { if (length == pageSize.value) {
length--; length--;
} }
var i = 0; var i = 0;
for (;i < length; i++) { for (; i < length; i++) {
let item: Item.PostProps = list.value[i]; let item: Item.PostProps = list.value[i];
if (!item.is_top) { if (!item.is_top) {
break; break;
} }
items.push(item); items.push(item);
} }
items.push(post); items.push(post);
for (;i < length; i++) { for (; i < length; i++) {
items.push(list.value[i]); items.push(list.value[i]);
} }
list.value = items; list.value = items;
}; };
const updatePage = (p: number) => { const nextPage = () => {
router.push({ page.value++;
name: 'home', loadPosts()
query: {
...route.query,
p,
},
});
}; };
onMounted(() => { onMounted(() => {
@ -142,14 +151,16 @@ watch(
}), }),
(to, from) => { (to, from) => {
if (to.refresh !== from.refresh) { if (to.refresh !== from.refresh) {
page.value = +(route.query.p as string) || 1; noMore.value = false;
page.value = 1;
setTimeout(() => { setTimeout(() => {
loadPosts(); loadPosts();
}, 0); }, 0);
return; return;
} }
if (from.path !== '/post' && to.path === '/') { if (from.path !== '/post' && to.path === '/') {
page.value = +(route.query.p as string) || 1; noMore.value = false;
page.value = 1;
setTimeout(() => { setTimeout(() => {
loadPosts(); loadPosts();
}, 0); }, 0);
@ -159,14 +170,36 @@ watch(
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.load-more {
margin: 20px;
.load-more-wrap {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
gap: 14px;
.load-more-spinner {
font-size: 14px;
opacity: 0.65;
}
}
}
.pagination-wrap { .pagination-wrap {
padding: 10px; padding: 10px;
display: flex; display: flex;
justify-content: center; justify-content: center;
overflow: hidden; overflow: hidden;
} }
.dark { .dark {
.main-content-wrap, .pagination-wrap, .empty-wrap, .skeleton-wrap {
.main-content-wrap,
.pagination-wrap,
.empty-wrap,
.skeleton-wrap {
background-color: rgba(16, 16, 20, 0.75); background-color: rgba(16, 16, 20, 0.75);
} }
} }

Loading…
Cancel
Save