PC-mj/pages/index.html/index.vue
DESKTOP-RQ919RC\Pc e8716bd33d fix(MyPopup): 修复收藏和发布列表显示问题,优化数据更新逻辑
refactor(app): 改进用户信息获取方式,使用事件监听替代轮询

style(details): 移除多余空格,优化HTML结构

perf(index): 替换nextTick为setTimeout延迟布局计算,提升性能

chore: 更新依赖和构建文件,清理无用资源
2025-06-26 16:21:45 +08:00

262 lines
6.6 KiB
Vue

<template>
<Head>
<Title>寄托天下 - 面经分享</Title>
<Meta name="keyword" content="留学资讯,留学交流论坛,留学面经,面试经验,寄托天下" />
</Head>
<TopHead></TopHead>
<div class="search-result flexacenter" v-if="keyword">
<div class="keyword flexacenter" @click="clearKeyword">{{ keyword }} <img class="keyword-icon" src="@/assets/img/cross-circle-icon.png" /></div>
<div class="halving-line"></div>
<div class="total"> {{ count }} 条搜索数据</div>
</div>
<div class="content" ref="gridContainer">
<div class="empty-box flexcenter" v-if="list.length == 0 && page == 0">
<empty hint="没有找到相关结果,请更换搜索关键词"></empty>
</div>
<template v-else>
<Item v-for="(item, index) in list" :key="index" :item="item" @handleLike="handleLike"></Item>
</template>
</div>
<div class="in-end" v-if="page == 0 && list.length > 0">- 到底了 -</div>
<div class="right-returnTop" v-if="returnTopState" @click="returnTop()">
<img src="@/assets/img/returnTop-icon.png" style="width: 24px; height: 24px" />
</div>
</template>
<script setup>
import { ElMessage } from "element-plus";
let isNeedLogin = inject("isNeedLogin");
const goLogin = inject("goLogin");
useHead({ script: [{ src: "https://app.gter.net/bottom?tpl=header&menukey=mj" }, { src: "https://app.gter.net/bottom?tpl=footer,popupnotification", body: true }] });
const gridContainer = ref(null);
let masonryInstance = null;
const route = useRoute();
let keyword = ref(""); // 搜索
keyword.value = route.query["keyword"];
watchEffect(() => {
if (keyword.value != route.query["keyword"]) {
list.value = [];
page.value = 1;
keyword.value = route.query["keyword"];
getList(route.query["keyword"]);
}
});
onMounted(async () => {
let Masonry = await import("masonry-layout");
masonryInstance = new Masonry.default(gridContainer.value, {
itemSelector: ".box",
gutter: 22.5,
});
// masonryInstance.reloadItems()
// masonryInstance.layout()
window.addEventListener("scroll", handleScroll);
getList();
});
const handleScroll = () => {
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
if (scrollTop > 200) returnTopState.value = true;
else returnTopState.value = false;
const scrollHeight = document.documentElement.scrollHeight;
const clientHeight = document.documentElement.clientHeight;
// 列表下 滑动到底部 获取新数据
if (scrollTop + clientHeight >= scrollHeight - 40) getList();
};
let page = ref(1);
let count = ref(0);
let list = ref([]); // 列表数据
let loading = false; // 加载中
const getList = () => {
if (page.value == 0 || loading) return;
loading = true;
getListHttp({ page: page.value, keyword: keyword.value })
.then((res) => {
if (res.code != 200) {
page.value = 0;
ElMessage({
message: res.message,
type: "error",
});
return;
}
let data = res.data;
// list.value = data.data
list.value = list.value.concat(data.data || []);
if (data.count > list.value.length) page.value++;
else page.value = 0;
count.value = data["count"];
setTimeout(() => {
if (!masonryInstance) return;
masonryInstance.reloadItems();
masonryInstance.layout();
}, 500);
})
.finally(() => (loading = false));
};
let user = inject("userInfo");
let openAttest = inject("openAttest");
const realname = inject("realname");
const handleLike = (token) => {
console.log(realname.value == 0, user.value.uin > 0);
if (realname.value == 0 && user.value.uin > 0) {
openAttest();
return;
}
if (isNeedLogin.value) {
goLogin();
return;
}
operateLikeHttp({ token }).then((res) => {
if (res.code != 200) return;
let data = res.data;
list.value.forEach((element) => {
if (element["token"] == token) {
element["islike"] = data["status"];
element["likenum"] = data["count"];
}
});
ElMessage.success(res.message);
});
};
onUnmounted(() => {
window.removeEventListener("scroll", handleScroll);
});
const router = useRouter();
// 清除搜索
// const clearKeyword = () => router.push(`/index.html`)
const clearKeyword = () => goToURL(`/index.html`, false);
try {
if (process.server) {
await getListHttp({ page: 1, keyword: keyword.value }).then((res) => {
if (res.code != 200) {
page.value = 0;
ElMessage({
message: res.message,
type: "error",
});
return;
}
let data = res.data;
list.value = list.value.concat(data.data || []);
});
}
} catch (error) {}
let returnTopState = ref(false);
const returnTop = () => {
window.scrollTo({
top: 0,
behavior: "smooth",
});
};
</script>
<style scoped lang="less">
.search-result {
width: 1200px;
margin: 0 auto 30px;
.keyword {
color: #fa6b11;
font-size: 14px;
cursor: pointer;
.keyword-icon {
width: 14px;
height: 14px;
margin-left: 9px;
}
}
.halving-line {
width: 1px;
height: 13px;
background: #d7d7d7;
margin: 0 20px;
}
.total {
font-size: 13px;
color: #7f7f7f;
}
}
.content {
min-height: calc(100vh - 250px);
width: 1200px;
// height: 1000px;
margin: 0 auto 93px;
display: flex;
flex-wrap: wrap;
// justify-content: space-between;
align-items: flex-start;
.empty-box {
width: 1200px;
height: 540px;
background-color: rgba(255, 255, 255, 1);
border-radius: 16px;
}
}
.in-end {
font-size: 12px;
color: #7f7f7f;
text-align: center;
margin-bottom: 88px;
}
.right-returnTop {
position: fixed;
right: calc((100vw - 1200px) / 2 - 75px);
width: 50px;
height: 50px;
background-color: #323232;
bottom: 85px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
z-index: 10;
cursor: pointer;
}
@media screen and (max-width: 1360px) {
.right-returnTop {
right: 0 !important;
}
}
</style>