mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-06 08:32:51 +08:00
✨ 页面触底加载
This commit is contained in:
41
src/hooks/reachBottom.ts
Normal file
41
src/hooks/reachBottom.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @file hooks/reachBottom.ts
|
||||
* @description 触底检测
|
||||
* @since Beta v0.7.7
|
||||
*/
|
||||
|
||||
import { onMounted, onUnmounted, ref, Ref } from "vue";
|
||||
|
||||
type ReachBottomReturn = {
|
||||
isReachBottom: Ref<boolean>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @function usePageReachBottom
|
||||
* @description 页面触底检测
|
||||
* @since Beta v0.7.7
|
||||
* @return ReachBottomReturn
|
||||
*/
|
||||
export function usePageReachBottom(): ReachBottomReturn {
|
||||
const isReachBottom = ref<boolean>(false);
|
||||
|
||||
const handleScroll = () => {
|
||||
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
|
||||
const clientHeight = document.documentElement.clientHeight || document.body.clientHeight;
|
||||
const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
|
||||
|
||||
// 检测是否触底
|
||||
isReachBottom.value = scrollTop + clientHeight >= scrollHeight - 1; // 减1是为了避免浮点数误差
|
||||
};
|
||||
|
||||
// 监听滚动事件
|
||||
onMounted(() => {
|
||||
window.addEventListener("scroll", handleScroll);
|
||||
// 初始检测
|
||||
handleScroll();
|
||||
});
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener("scroll", handleScroll);
|
||||
});
|
||||
return { isReachBottom };
|
||||
}
|
||||
@@ -115,12 +115,6 @@
|
||||
<TPostCard :model-value="post" :user-click="true" @onUserClick="handleUserClick" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="posts-load-more">
|
||||
<v-btn class="post-forum-btn" :rounded="true" @click="loadMore()">
|
||||
已加载:{{ posts.length }},
|
||||
{{ postRaw.isLast ? "已加载完毕" : "加载更多" }}
|
||||
</v-btn>
|
||||
</div>
|
||||
<VpOverlaySearch :gid="curGid.toString()" v-model="showSearch" :keyword="search" />
|
||||
<VpOverlayUser v-model="showUser" :gid="curGid" :uid="curUid" />
|
||||
</template>
|
||||
@@ -132,6 +126,7 @@ import showLoading from "@comp/func/loading.js";
|
||||
import showSnackbar from "@comp/func/snackbar.js";
|
||||
import VpOverlaySearch from "@comp/viewPost/vp-overlay-search.vue";
|
||||
import VpOverlayUser from "@comp/viewPost/vp-overlay-user.vue";
|
||||
import { usePageReachBottom } from "@hooks/reachBottom.js";
|
||||
import ApiHubReq from "@req/apiHubReq.js";
|
||||
import painterReq from "@req/painterReq.js";
|
||||
import useBBSStore from "@store/bbs.js";
|
||||
@@ -158,6 +153,8 @@ const curSortType = ref<number>(1);
|
||||
const firstLoad = ref<boolean>(false);
|
||||
const isReq = ref<boolean>(false);
|
||||
|
||||
const { isReachBottom } = usePageReachBottom();
|
||||
|
||||
const search = ref<string>("");
|
||||
const showSearch = ref<boolean>(false);
|
||||
const curUid = ref<string>("");
|
||||
@@ -193,6 +190,13 @@ onMounted(async () => {
|
||||
await freshPostData();
|
||||
firstLoad.value = true;
|
||||
});
|
||||
watch(
|
||||
() => isReachBottom.value,
|
||||
async () => {
|
||||
if (!isReachBottom.value) return;
|
||||
await loadMore();
|
||||
},
|
||||
);
|
||||
watch(
|
||||
() => curGid.value,
|
||||
() => {
|
||||
@@ -403,15 +407,6 @@ function handleUserClick(user: TGApp.BBS.Post.User, gid: number): void {
|
||||
grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
|
||||
}
|
||||
|
||||
.posts-load-more {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 10px;
|
||||
font-family: var(--font-title);
|
||||
transition: all 0.3s linear;
|
||||
}
|
||||
|
||||
.select-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
||||
@@ -50,12 +50,6 @@
|
||||
<TPostCard :model-value="item" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="load-news">
|
||||
<v-btn class="post-news-btn" :rounded="true" :loading="loading" @click="loadMore(value)">
|
||||
已加载:{{ rawData[value].lastId }},
|
||||
{{ rawData[value].isLast ? "已加载完毕" : "加载更多" }}
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-window-item>
|
||||
</v-window>
|
||||
<ToChannel v-model="showList" :gid="gid" />
|
||||
@@ -67,13 +61,14 @@ import showLoading from "@comp/func/loading.js";
|
||||
import showSnackbar from "@comp/func/snackbar.js";
|
||||
import ToChannel from "@comp/pageNews/to-channel.vue";
|
||||
import VpOverlaySearch from "@comp/viewPost/vp-overlay-search.vue";
|
||||
import { usePageReachBottom } from "@hooks/reachBottom.js";
|
||||
import painterReq from "@req/painterReq.js";
|
||||
import useAppStore, { type NewsType } from "@store/app.js";
|
||||
import useBBSStore from "@store/bbs.js";
|
||||
import TGLogger from "@utils/TGLogger.js";
|
||||
import { createPost } from "@utils/TGWindow.js";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { computed, onMounted, reactive, Ref, ref, shallowRef } from "vue";
|
||||
import { computed, onMounted, reactive, Ref, ref, shallowRef, watch } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
|
||||
type PostData = { [key in NewsType]: Ref<Array<TGApp.BBS.Post.FullData>> };
|
||||
@@ -85,6 +80,8 @@ const { recentNewsType } = storeToRefs(useAppStore());
|
||||
const { gameList } = storeToRefs(useBBSStore());
|
||||
const { gid } = <{ gid: string }>useRoute().params;
|
||||
|
||||
const { isReachBottom } = usePageReachBottom();
|
||||
|
||||
const tabValues: Readonly<Array<NewsType>> = ["notice", "activity", "news"];
|
||||
const tabMap: Readonly<Record<NewsType, string>> = { notice: "1", activity: "2", news: "3" };
|
||||
const label = computed<string>(() => {
|
||||
@@ -113,6 +110,14 @@ const tab = computed<NewsType>({
|
||||
|
||||
onMounted(async () => await firstLoad(tab.value));
|
||||
|
||||
watch(
|
||||
() => isReachBottom.value,
|
||||
async () => {
|
||||
if (!isReachBottom.value) return;
|
||||
await loadMore(tab.value);
|
||||
},
|
||||
);
|
||||
|
||||
async function firstLoad(key: NewsType, refresh: boolean = false): Promise<void> {
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
@@ -191,7 +196,7 @@ async function searchPost(): Promise<void> {
|
||||
showSearch.value = false;
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
<style lang="scss" scoped>
|
||||
.news-tab {
|
||||
margin-bottom: 10px;
|
||||
color: var(--common-text-title);
|
||||
@@ -230,15 +235,4 @@ async function searchPost(): Promise<void> {
|
||||
grid-gap: 8px;
|
||||
grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
|
||||
}
|
||||
|
||||
/* load more */
|
||||
|
||||
.load-news {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 10px;
|
||||
font-family: var(--font-title);
|
||||
transition: all 0.3s linear;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -23,14 +23,15 @@
|
||||
"@styles/*": ["src/assets/styles/*"],
|
||||
"@comp/*": ["src/components/*"],
|
||||
"@enum/*": ["src/enum/*"],
|
||||
"@hooks/*": ["src/hooks/*"],
|
||||
"@Bili/*": ["src/plugins/Bili/*"],
|
||||
"@Hutao/*": ["src/plugins/Hutao/*"],
|
||||
"@Mys/*": ["src/plugins/Mys/*"],
|
||||
"@Sql/*": ["src/plugins/Sqlite/*"],
|
||||
"@Sqlm/*": ["src/plugins/Sqlite/modules/*"],
|
||||
"@utils/*": ["src/utils/*"],
|
||||
"@req/*": ["src/request/*"],
|
||||
"@store/*": ["src/store/modules/*"],
|
||||
"@req/*": ["src/request/*"]
|
||||
"@utils/*": ["src/utils/*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
|
||||
@@ -22,6 +22,7 @@ export default defineConfig({
|
||||
"@styles/": "/src/assets/styles/",
|
||||
"@comp/": "/src/components/",
|
||||
"@enum/": "/src/enum/",
|
||||
"@hooks/": "/src/hooks/",
|
||||
"@Bili/": "/src/plugins/Bili/",
|
||||
"@Hutao/": "/src/plugins/Hutao/",
|
||||
"@Mys/": "/src/plugins/Mys/",
|
||||
|
||||
Reference in New Issue
Block a user