vue3 element plus 無限スクロール

# 無限スクロール最新版

# 追記

データが13件のとき、すべてを読み込み、元のページに戻る、リロードをすると同じページを読み込んでしまうのを防止。

```hoge.vue
<template>

    <h1 class="title">アンサーショー</h1>
    <div class="infinite-list-wrapper">
        <div>
            <div v-infinite-scroll="load" class="list" :infinite-scroll-disabled="disabled" infinite-scroll-distance="150">
                <div v-for="(v,key) in infShow" :key="key" style="border-bottom:1px solid #ededed;">
                    <h2>{{key}} {{v.id}}</h2>
                </div>
                <p v-if="loading">Loading...</p>
                <p v-if="noMore">すべて読み込みました</p>
            </div>
        </div>
    </div>

</template>





<script lang="ts" setup>

import {ref, onMounted, inject, reactive} from 'vue';
import axios from 'axios';
import { useStoreUser } from '/resources/user';
const user = useStoreUser();
import {useRoute, useRouter} from 'vue-router';
const route = useRoute()//route.params.id を取得するのに必要
const router = useRouter();


const axiosUrl = ref()
const infShow = ref(reactive([]))
const loading = ref(false)
const noMore = ref(false)
const disabled = ref(false)
const readedUrl = reactive<string[]>([]);


const load = () => {
    loading.value = true
    setTimeout(() => {
        getShow()
        loading.value = false
    }, 200)
}

const getShow = () => {

    if (!readedUrl.includes(axiosUrl.value)) {
        readedUrl.push(axiosUrl.value);
        if(axiosUrl.value != null){

            axios.post(axiosUrl.value)
                .then(response => {

                    router.replace({
                        path: route.path,
                        query:{
                            page: response.data.res.current_page
                        }
                    }, () => {}, () => {});

                    axiosUrl.value = response.data.res.next_page_url;
                    infShow.value.push(...response.data.res.data);

                    //ページ遷移対策で、sessionstorageにデータを保存
                    sessionStorage.setItem(route.name,JSON.stringify(infShow.value));

                    //最大件数も保存
                    sessionStorage.setItem(route.name + 'total',JSON.stringify(response.data.res.total));


                    if(response.data.res.next_page_url == null){
                        disabled.value = true
                        noMore.value = true
                    }

                })
                .catch(error => {
                    // エラーを処理する
                    disabled.value = true
                    noMore.value = true
                    console.error(error)
                })
        }

    } else {

        console.log("アクシオスurlがreadurlにあります");

    }
}

onMounted(() => {
    //最初に user_id をつける


    let page = 1;
    if(route.query.page){

        let total = JSON.parse(sessionStorage.getItem(route.name + 'total'));

        let savedValue = JSON.parse(sessionStorage.getItem(route.name));

        if(Array.isArray(savedValue)) {
            savedValue.forEach(item => infShow.value.push(item));
        }

        //読み込んだデータとトータルの数が同じであれば、それ以上読み込まない
        //(ページ遷移時に限界突破して読み込むのを防ぐ)
        if(infShow.value.length == total){
            disabled.value = true
            noMore.value = true
            console.log("トータルカウントが同じなのでこれ以上読み込みません。");
        }

    } else {
        sessionStorage.removeItem(route.name);
    }

    axiosUrl.value　= "/answers/show?page=" + route.query.page


    console.log("mounted...");
});

</script>




```




#追記

戻る　をした時にデータを復元
最下部の url だけ変更すりゃコピペで動く。

```
<template>
    <div class="infinite-list-wrapper">
        <div v-infinite-scroll="load"
                class="list"
                :infinite-scroll-disabled="disabled"
                infinite-scroll-distance="150">
            <div
                v-for="(v,key) in infShow" :key="key"
                :span="12">
                <RouterLink :to="{ path: '/'+v.id+'/'}">{{key}} : {{v.id}}</RouterLink>
            </div>
        </div>
        <p v-if="loading" style="background-color: red;">Loading...</p>
        <p v-if="noMore">すべて読み込みました</p>
    </div>
</template>


<script lang="ts" setup>
import {ref, onMounted,reactive} from 'vue';
import {useRoute, useRouter} from 'vue-router';
import axios from "axios";
const route = useRoute()//route.params.id を取得するのに必要
const router = useRouter();
const axiosUrl = ref()
const infShow = ref(reactive([]))
const loading = ref(false)
const noMore = ref(false)
const disabled = ref(false)
const readedUrl = reactive<string[]>([]);

const load = () => {
    loading.value = true
    setTimeout(() => {
        getShow()
        loading.value = false
    }, 200)
}

const getShow = () => {

    if (!readedUrl.includes(axiosUrl.value)) {
        readedUrl.push(axiosUrl.value);
        if(axiosUrl.value != null){
            axios.post(axiosUrl.value)
                .then(response => {
                    router.push({
                        path: route.path,
                        query:{
                            page: response.data.res.current_page,
                        }
                    }, () => {}, () => {});
                    axiosUrl.value = response.data.res.next_page_url;
                    infShow.value.push(...response.data.res.data);
                    sessionStorage.setItem(route.name,JSON.stringify(infShow.value));
                    if(response.data.res.next_page_url == null){
                        disabled.value = true
                        noMore.value = true
                    }
                })
                .catch(error => {
                    // エラーを処理する
                    disabled.value = true
                    noMore.value = true
                    console.error(error)
                })
        }

    }
}


onMounted(() => {

    let page = 1;
    if(route.query.page){
        page = route.query.page;
        let savedValue = JSON.parse(sessionStorage.getItem(route.name));
        if(Array.isArray(savedValue)) {
            savedValue.forEach(item => infShow.value.push(item));
        }
    } else {
        sessionStorage.removeItem(route.name);
    }

    //url整形
    axiosUrl.value　= "/questions/show?page=" + page
});

</script>



```

シンプルに。


同じページ何度も読み込まないようにしてある。
`readedUrl.push(axiosUrl.value);`
が味噌ですわ。

```hoge.vue
<template>

    <div class="infinite-list-wrapper">

        <el-row v-infinite-scroll="load"
                class="list"
                :infinite-scroll-disabled="disabled"
                infinite-scroll-distance="150">
            <el-col
                v-for="(v,key) in userShow" :key="key"
                :span="12">
                <div class="list-item">
                    <a style="cursor:pointer">{{key}} : {{v.id}} {{v.name}}</a>
                </div>
            </el-col>
        </el-row>

        <p v-if="loading" style="background-color: red;">Loading...</p>
        <p v-if="noMore">すべて読み込みました</p>

    </div>


</template>





<script lang="ts" setup>
import {  reactive, ref } from 'vue'



const child = ref();
const direction = ref('btt')
const size = ref(`100%`)
const lock = ref(true)
const axiosUrl = ref(`/users/show`)

const userShow = ref(reactive([]))
const loading = ref(false)
const noMore = ref(false)
const disabled = ref(false)
const readedUrl = reactive<string[]>([]);


const load = () => {
    loading.value = true
    setTimeout(() => {
        getShow()
        loading.value = false
    }, 200)
}


const getShow = () => {

    if (!readedUrl.includes(axiosUrl.value)) {
        readedUrl.push(axiosUrl.value);

        console.log("ページを読み込みます" + axiosUrl.value);

        if(axiosUrl.value != null){
            axios.post(axiosUrl.value)
                .then(response => {

                    console.log(response.data.res);

                    axiosUrl.value = response.data.res.next_page_url;
                    userShow.value.push(...response.data.res.data);

                    if(response.data.res.next_page_url == null){
                        disabled.value = true
                        noMore.value = true
                    }

                })
                .catch(error => {
                    // エラーを処理する
                    disabled.value = true
                    noMore.value = true
                    console.error(error)
                })
        }

    }
}


</script>

<style scoped>
.infinite-list-wrapper {
    height: 50%;
    text-align: center;
}
.infinite-list-wrapper .list {
    padding: 0;
    margin: 0;
    list-style: none;
}

.infinite-list-wrapper .list-item {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 150px;
    background: var(--el-color-danger-light-9);
    color: var(--el-color-danger);
}
.infinite-list-wrapper .list-item + .list-item {
    margin-top: 10px;
}
</style>

```