From dbdcfa84fd62e7c2c1362f0506ef21c2ae4b7fdf Mon Sep 17 00:00:00 2001 From: KUN1007 Date: Fri, 15 Sep 2023 21:45:44 +0800 Subject: [PATCH] feat: lazy load reply --- src/store/modules/topic.ts | 22 ++- src/views/topic/KUNGalgameTopicPage.vue | 88 +++++++++-- src/views/topic/aside/Aside.vue | 4 +- .../topic/components/KUNGalgamerInfo.vue | 1 - src/views/topic/components/Master.vue | 1 + src/views/topic/components/Reply.vue | 141 ++++++++---------- 6 files changed, 153 insertions(+), 104 deletions(-) diff --git a/src/store/modules/topic.ts b/src/store/modules/topic.ts index c32d7a3d..d4728846 100644 --- a/src/store/modules/topic.ts +++ b/src/store/modules/topic.ts @@ -44,6 +44,11 @@ interface CommentDraft { content: string } +// 获取回复的请求 +interface ReplyRequest { + sortField: string + sortOrder: 'asc' | 'desc' +} // 话题页面的 store interface Topic { // 是否正在被编辑 @@ -56,7 +61,7 @@ interface Topic { // 回复的缓存 replyDraft: ReplyDraft // 获取回复的请求接口格式 - replyRequest: TopicReplyRequestData + replyRequest: ReplyRequest // 评论的缓存 commentDraft: CommentDraft @@ -81,11 +86,8 @@ export const useKUNGalgameTopicStore = defineStore({ publishStatus: false, }, replyRequest: { - tid: 0, - page: 1, - limit: 5, sortField: '', - sortOrder: '', + sortOrder: 'asc', }, commentDraft: { c_uid: 0, @@ -135,13 +137,17 @@ export const useKUNGalgameTopicStore = defineStore({ }) }, // 获取回复 - getReplies(tid: number): Promise { + getReplies( + tid: number, + page?: number, + limit?: number + ): Promise { return new Promise((resolve, reject) => { // 这里的默认值用于初始化 const requestData: TopicReplyRequestData = { tid: tid, - page: this.replyRequest.page || 1, - limit: this.replyRequest.limit || 5, + page: page || 1, + limit: limit || 5, sortField: this.replyRequest.sortField || 'floor', sortOrder: this.replyRequest.sortOrder || 'desc', } diff --git a/src/views/topic/KUNGalgameTopicPage.vue b/src/views/topic/KUNGalgameTopicPage.vue index b840efb7..9561e6b6 100644 --- a/src/views/topic/KUNGalgameTopicPage.vue +++ b/src/views/topic/KUNGalgameTopicPage.vue @@ -9,8 +9,11 @@ import { onBeforeMount, computed, watch, + onBeforeUnmount, } from 'vue' -import { onBeforeRouteLeave } from 'vue-router' +import { onBeforeRouteLeave, useRoute } from 'vue-router' + +import { TopicDetail, TopicReply } from '@/api' // Aside import Aside from './aside/Aside.vue' @@ -25,13 +28,9 @@ const ReplyPanel = defineAsyncComponent( import { useKUNGalgameSettingsStore } from '@/store/modules/settings' // 导入话题页面 store import { useKUNGalgameTopicStore } from '@/store/modules/topic' - import { storeToRefs } from 'pinia' -import { TopicDetail, TopicReply } from '@/api' - -import { useRoute } from 'vue-router' - +// 当前的路由 const route = useRoute() // 使用设置面板的 store @@ -51,18 +50,20 @@ const tid = computed(() => { const topicData = ref() // 单个话题的回复数据 const repliesData = ref([]) +// 页面的容器,用于计算是否到达底部 +const content = ref() +// 当前的页数 +const currentPage = ref(1) +// 是否加载,因为已经加载完了 +const isLoading = ref(true) -const fetchTopicData = async () => { +/** 这里拿到的已经是后端返回回来的 data 数据了 */ +onMounted(async () => { // 获取单个话题的数据 const topicResponseData = ( await useKUNGalgameTopicStore().getTopicByTid(tid.value) ).data topicData.value = topicResponseData -} - -/** 这里拿到的已经是后端返回回来的 data 数据了 */ -onMounted(async () => { - await fetchTopicData() }) // 调用 getReplies 获取回复数据(watch 大法好!) @@ -73,13 +74,66 @@ watch( replyDraft.value.publishStatus, ], async () => { - repliesData.value = ( + const replyResponseData = ( await useKUNGalgameTopicStore().getReplies(tid.value) ).data + repliesData.value = replyResponseData }, { immediate: true } ) +// 滚动事件处理函数 +const scrollHandler = async () => { + // 滚动到底部的处理逻辑 + if (isScrollAtBottom() && isLoading.value) { + // 自动增加页数 + currentPage.value++ + // 获取下一页的回复数据 + + const lazyLoadReplies = await useKUNGalgameTopicStore().getReplies( + tid.value, + currentPage.value + ) + + // 判断是否已经将数据加载完,加载完则不需要加载了 + if (!lazyLoadReplies.data.length) { + isLoading.value = false + } + + // 将新加载的回复数据追加到已有的回复数据中 + repliesData.value = [...repliesData.value, ...lazyLoadReplies.data] + } +} + +// 判断是否滚动到底部 +const isScrollAtBottom = () => { + if (content.value) { + const scrollHeight = content.value.scrollHeight + const scrollTop = content.value.scrollTop + const clientHeight = content.value.clientHeight + + return scrollHeight - scrollTop === clientHeight + } +} + +// 在组件挂载后,添加滚动事件监听器 +onMounted(() => { + // 获取滚动元素的引用 + const element = content.value + + if (element) { + element.addEventListener('scroll', scrollHandler) + } +}) + +// 在组件卸载前,移除滚动事件监听器 +onBeforeUnmount(() => { + const element = content.value + + if (element) { + element.removeEventListener('scroll', scrollHandler) + } +}) /* 话题界面的页面宽度 */ const topicPageWidth = computed(() => { return showKUNGalgamePageWidth.value.Topic + '%' @@ -112,7 +166,7 @@ onBeforeMount(() => {