Vue.js

InfiniteLoading 無限スクロール vue.js

vue.jsすげーな。

中国でめっちゃ発達しているし、コードもきれい。

レベル上がってきたな。。。

ということで今回は無限スクロールさせちゃいましょう。

そこら辺に書いてあるコードだといろいろエラーが出たり、

動かなかったりする。

検索条件を変更するには


this.$refs.infiniteLoading.stateChanger.reset();

追記。

pulltoとかのライブラリと併用しようとしたがうまくいかない。

オプション変更したい場合


hoge.vue


// app.js でも import して、さらに このMugen.vue でもimportするのが味噌
import InfiniteLoading from 'vue-infinite-loading';

Vue.use(InfiniteLoading, {
slots: {
noMore: 'すべて読み込みました', // you can pass a string value
noResults: '読み込み完了しています', // you can pass a string value

},
});


参考

https://blog.csdn.net/zfangls/article/details/72727198


インストール

npm install vue-infinite-loading --save


app.js


import InfiniteLoading from 'vue-infinite-loading';


コード

elementui を使っているとバグるみたい。

読み込みまくって止まらない。ということで、

force-use-infinite-wrapper="true"

を忘れずに。


<template>
<div class="list-con">

<div class="list" v-for="(item,key) in list">
<span v-text="key+1"></span>
<p>
<a :href="item.url">{{item.title}}</a>
</p>
</div>

<infinite-loading force-use-infinite-wrapper="true" @infinite="onInfinite" ref="infiniteLoading" :distance="1000"></infinite-loading>

</div>
</template>

<script>

// app.js でも import して、さらに このMugen.vue でもimportするのが味噌
import InfiniteLoading from 'vue-infinite-loading';

//あえてページは指定しない
const api = 'https://hn.algolia.com/api/v1/search_by_date?tags=story&page=';

export default {
components: {
InfiniteLoading,
},
data() {
return {
list:[]
}
},
mounted: function() {

},
created(){

},
methods: {

onInfinite() {

let page = this.list.length / 20 + 1;

console.log(page);

axios.get(api+page)
.then(function (res) {

if (res.data.hits.length) {

//今まで読みこんだ配列に、新しく読み込んだ配列を結合
this.list = this.list.concat(res.data.hits);

// this.$router.push("/mugen?page=" + page);

console.log("現在のスクロール位置" + window.scrollY);
this.$router.push({
path: "/mugen?page=" + page + "&y=" + window.scrollY,
});

this.$refs.infiniteLoading.stateChanger.loaded();

//10ページ目まで読み込んだらそれ以上は読み込ませない
if (this.list.length / 20 === 10) {
console.log("大量にデータがあるのでここで終了しておきます。");
this.$refs.infiniteLoading.stateChanger.complete();
}
} else {
//データがなけりゃそれ以上読み込ませない
console.log("全て読み込ました");
this.$refs.infiniteLoading.stateChanger.complete();
}

// bind しておくことで、 axios、then 内で this や page を 使えるようにする
}.bind(this).bind(page))
.catch(function (error) {
console.log(error);
});

}
}
}
</script>

<style scoped>
.list{
overflow:hidden;
margin:20px 0;
}
span{
float: left;
margin-right: 5px;
}
p{
float: left;
}
</style>


おまけ

さらに早く読み込みたい!

ってときは distance を指定する。


<infinite-loading @infinite="onInfinite" ref="infiniteLoading" :distance="1000">
<span slot="no-more">すべて読み込みました</span>
</infinite-loading>


laravel との併用

laravel のコントローラーで


// ユーザー一覧を表示
public function show()
{

$res = User::query()->paginate(25);

return response()->json($res);

}

これでユーザー情報を 25人分表示せよと。


<template>

<div>

<div class="list-con">
<div class="list" v-for="(item,key) in list">
<p>
{{item.id}} : {{item.name}}
</p>
</div>
<infinite-loading @infinite="onInfinite" ref="infiniteLoading" :distance="500">
<span slot="no-more">すべて読み込みました</span>
</infinite-loading>
</div>

</div>

</template>
<script>

// app.js でも import して、さらに このMugen.vue でもimportするのが味噌
import InfiniteLoading from 'vue-infinite-loading';

export default {
components: {
InfiniteLoading,
},
data() {
return {
list:[],
nextUrl:'/user/show/'
}
},
mounted: function() {

},
created(){

},
methods: {

onInfinite() {

axios.get(this.nextUrl).then(e => {

// console.log(e.data);
// //メインデータ
// console.log(e.data.data);
//
//
// //次のページのURL
// console.log(e.data.next_page_url);

if (e.data.data.length) {

//今まで読みこんだ配列に、新しく読み込んだ配列を結合
this.list = this.list.concat(e.data.data);
this.$refs.infiniteLoading.stateChanger.loaded();
this.$router.push("/show?page=" + e.data.current_page);

this.nextUrl = e.data.next_page_url;

//現在のページ と 最後のページが同一なら終了
if (e.data.current_page == e.data.last_page) {
alert("読み込み完了しました");
this.$refs.infiniteLoading.stateChanger.complete();
}

} else {
//データがなけりゃそれ以上読み込ませない
this.$refs.infiniteLoading.stateChanger.complete();
}

// console.log(e.data);

}).catch((error) => {

console.log(error);
console.log("エラー");

});

}
}
}
</script>

<style scoped>
.list{
overflow:hidden;
margin:20px 0;
}
span{
float: left;
margin-right: 5px;
}
p{
float: left;
}
</style>

何が素晴らしいって、laravel の paginate は最後のページ数とかも計算してくれるので簡単にvue.jsと連携できるのがすごい。


セッションストレージでキャッシュをとっておく


<template>

<div>

<div style="margin-top: 45px;">
現在のページ数 {{page}}
</div>

<div class="list" v-for="(item,key) in list">
<span v-text="key+1"></span>
<p>
<a v-touch="$root.linkTo('/user/10049/')">{{item.title}}</a>
</p>
</div>

<infinite-loading force-use-infinite-wrapper="true" @infinite="onInfinite" ref="infiniteLoading" :distance="1000"></infinite-loading>

</div>

</template>

<script>

// app.js でも import して、さらに このMugen.vue でもimportするのが味噌
import InfiniteLoading from 'vue-infinite-loading';

//あえてページは指定しない
const api = 'https://hn.algolia.com/api/v1/search_by_date?tags=story&page=';

export default {
components: {
InfiniteLoading
},
data() {
return {
list:[],
page:1,
}
},

mounted() {

//ブラウザ戻るできた場合は必ず page があるので。
//これでバックしてきたと判断する

if(this.$route.query.page){

// console.log("ページあるで");
if (sessionStorage.list) {
this.list = JSON.parse(sessionStorage.getItem('list'));
console.log(this.list);
}

if (sessionStorage.page) {
this.page = sessionStorage.getItem('page');
console.log(this.page);
}

} else {
//他の画面を経由して来た場合は検索結果をリセット
sessionStorage.clear();
}

},

created(){

},
methods: {

onInfinite() {

if(this.page < 10){

this.page = this.list.length / 20 + 1;
sessionStorage.page = this.page;

axios.get(api+this.page).then(res => {

if (res.data.hits.length) {

//今まで読みこんだ配列に、新しく読み込んだ配列を結合
this.list = this.list.concat(res.data.hits);

sessionStorage.list = JSON.stringify(this.list);

this.$router.push({
path: "/mugen?page=" + this.page + "&y=" + window.scrollY,
});

this.$refs.infiniteLoading.stateChanger.loaded();

//10ページ目まで読み込んだらそれ以上は読み込ませない
if (this.page >= 10) {
console.log("大量にデータがあるのでここで終了しておきます。");
this.$refs.infiniteLoading.stateChanger.complete();
}
} else {
//データがなけりゃそれ以上読み込ませない
console.log("全て読み込ました");
this.$refs.infiniteLoading.stateChanger.complete();
}

console.log("成功");
}).catch((error) => {
console.log("エラー");
});

} else {
console.log("セッションストレージですでにマックス。");
this.$refs.infiniteLoading.stateChanger.complete();
}
},

refresh(loaded) {

alert("再読込完了");

loaded('done');
}
}
}
</script>

<style scoped>
.list{
overflow:hidden;
margin:20px 0;
}
span{
float: left;
margin-right: 5px;
}
p{
float: left;
}
</style>