62 lines
1.7 KiB
Vue
62 lines
1.7 KiB
Vue
<script setup>
|
|
import { useArticleStore } from '@/stores/article'
|
|
import { useScroll } from '@vueuse/core'; // Changed to useScroll as a simpler alternative
|
|
import { onMounted, ref, watch } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
|
|
const router = useRouter()
|
|
const store = useArticleStore()
|
|
const searchInput = ref('')
|
|
const loadingTrigger = ref(null)
|
|
|
|
const el = ref(null)
|
|
const { y, isScrolling } = useScroll(el)
|
|
|
|
watch(y, (newY) => {
|
|
if (!store.loading && !isScrolling && newY > 0) {
|
|
const scrollHeight = el.value.scrollHeight
|
|
const scrollTop = newY
|
|
const clientHeight = el.value.clientHeight
|
|
|
|
if (scrollHeight - scrollTop - clientHeight < 50) {
|
|
store.fetchArticles()
|
|
}
|
|
}
|
|
})
|
|
|
|
const showArticle = (id) => {
|
|
router.push(`/article/${id}`)
|
|
}
|
|
|
|
const handleSearch = () => {
|
|
store.setSearchQuery(searchInput.value)
|
|
}
|
|
|
|
onMounted(() => {
|
|
if (store.articles.length === 0) {
|
|
store.fetchArticles()
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div class="article-list" ref="el">
|
|
<div class="search-bar p-2">
|
|
<InputText v-model="searchInput" placeholder="搜索文章" class="w-full" />
|
|
<Button @click="handleSearch">搜索</Button>
|
|
</div>
|
|
|
|
<div class="articles p-2">
|
|
<Card v-for="article in store.articles" :key="article.id" class="mb-2 article-card"
|
|
@click="showArticle(article.id)">
|
|
<template #title>{{ article.title }}</template>
|
|
<template #content>{{ article.summary }}</template>
|
|
</Card>
|
|
|
|
<div ref="loadingTrigger" v-show="store.hasMore">
|
|
<ProgressSpinner v-if="store.loading" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|