基本的に How to integrate Infinite Loading with Gridsome この記事を見ればお k なんだけど、vue の mixin をつくって汎用的にする方法を書く。 例えばトップページと Tag ページ両方 infinitescroll 実装したいけど同じようなコードを書くのは冗長なので共通化したい時。
./src/mixins
フォルダを作ってその中に InfiniteScrollMixin.js などを作成
./src/mixins/InfiniteScrollMixin.js
export default {
data() {
return {
loadedPosts: [],
currentPage: 1,
};
},
computed: {
fetchEndpoint() {
return ``;
},
},
watch: {
$route(to, from) {
this.refleshPosts();
},
},
created() {
this.infiniteInit();
},
methods: {
infiniteInit() {
this.loadedPosts.push(...this.$page.posts.edges);
},
refleshPosts() {
this.currentPage = 1;
this.loadedPosts = [];
if (this.$refs.InfiniteLoading) {
this.$refs.InfiniteLoading.stateChanger.reset();
}
if (this.$page.posts) {
this.loadedPosts.push(...this.$page.posts.edges);
}
},
wait() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 500);
});
},
async fetch() {
const { data } = await this.$fetch(
`${this.fetchEndpoint}/${this.currentPage + 1}`
);
return data;
},
async infiniteHandler($state) {
if (this.currentPage + 1 > this.$page.posts.pageInfo.totalPages) {
$state.complete();
} else {
await this.wait();
const data = await this.fetch();
if (data.posts.edges.length) {
this.currentPage = data.posts.pageInfo.currentPage;
this.loadedPosts.push(...data.posts.edges);
$state.loaded();
} else {
$state.complete();
}
}
},
},
};
参考記事と基本は同じだけど、汎用的にするためにfetchEndpoint
method があるのと、
ページ遷移させた時に refresh させたい用途でrefreshPosts
method を route を watch して実行している。
wait
method は基本待機時間設定を雑にしてるだけなのでいらなかったら削除して構わない。promise.all しといた方がほんとはよいがな。
で、infinitescroll を実行したいページで以下のように
./src/template/Tag.js
<template lang="pug">
Layout
.articles
transitionGroup(name="fade")
ItemLimt(:items="loadedPosts", key="tag")
ClientOnly
infinite-loading(@infinite="infiniteHandler",spinner="spiral", ref="InfiniteLoading")
div(slot="no-more") You've scrolled through all the posts ;)
div(slot="no-results") Sorry, no posts yet :(
</template>
<page-query>
query($id: ID!, $page: Int) {
allTag(filter: { id : { eq : $id }}) {
edges {
node {
id
}
}
}
posts: allArticle(filter: { tags: { contains: [$id] }}, perPage: 3, page: $page) @paginate {
pageInfo{
totalPages
currentPage
}
edges {
node {
id
title
date
path
catch
meta {
description
}
tags {
id
path
}
content
}
}
}
}
</page-query>
<script>
import itemLimt from "@components/itemList.vue";
import InfiniteScrollMixin from "@mixins/InfiniteScrollMixin.js";
export default {
components: {
ItemLimt: itemLimt,
},
mixins: [InfiniteScrollMixin],
metaInfo() {
return {
title: `${this.tagID}`,
};
},
computed: {
tagID() {
return this.$page.allTag.edges[0].node.id;
},
fetchEndpoint() {
return `/tags/${this.tagID}`;
},
},
async mounted() {},
methods: {},
beforeDestroy() {},
};
</script>
<style lang="stylus" scoped></style>
mixin を継承したファイル上で fetchEndpoint で endpoint を返してあげれば終わり。 infinitescroll を実装したいファイルで同じように継承して使ってあげれば良い。便利やね。