Laravel/Inertia.js

검색 필터 및 더보기 구현(#Filter #Search #LoadMore)

짱구를왜말려? 2021. 11. 16. 15:16
반응형
SMALL

# What?

스크롤 유지하면서 리스트 필터링 및 더보기 구현

 

# Why?

요즘은 페이지 바뀌면서 스크롤 초기화되는거 지양

 

# How?

1. form을 watch로 검사하지 말고 각 input에 @change를 걸어 filter 메소드 호출하게 하기

 

2.  preserveScroll : true 옵션으로 스크롤 유지하기

 

3. replace: true 옵션으로 페이지 히스토리를 남기지 않고 뒤로가기 시 진짜 이전 페이지로 이동하게끔 하기(안그러면 필터값 바꿀때마다의 페이지 히스토리 다 남아서 뒤로가기 시 몇번을 눌러대야함)

 

4. preserveState : true 옵션으로 더보기 구현 시 이전 데이터 리스트에 새로 불러온 데이터 리스트를 추가하기

 

<template>
    <div class="subContent area-workerList">
        <div class="wrap">
            <div class="m-input-checkboxes type01">
                <div class="m-input-checkbox type01">
                    <input type="checkbox" checked="checked" v-if="form.category_ids.length === 0">
                    <input type="checkbox" v-else>
                    <label for="" @click="clearCategories">전체</label>
                </div>
                <div class="m-input-checkbox type01" v-for="category in categories.data" :key="category.id" @change="filter">
                    <input type="checkbox" :id="category.id" :value="category.id" v-model.lazy="form.category_ids">
                    <label :for="category.id">{{ category.title }}</label>
                </div>
            </div>

            <div class="m-input-top type01">
                <div class="inputs">
                    <div class="m-input-select type01">
                        <select name="" id="" v-model.lazy="form.orderBy" @change="filter">
                            <option value="count_request">인기순</option>
                            <option value="created_at">최신순</option>
                        </select>
                    </div>

                    <form @submit.prevent="filter">
                        <div class="m-input-text type01">
                            <input type="text" placeholder="전문가명" v-model.lazy="form.word">

                            <img src="/img/search.png" alt="" class="m-input-text-deco" @click="filter">
                        </div>
                    </form>
                </div>
            </div>

            <div class="m-empty type01" v-if="workers.data.length === 0">
                데이터가 없습니다.
            </div>

            <workers :items="workers.data" v-else />

            <div class="m-btns type01 mt-80" v-if="workers.links.next">
                <button class="m-btn type01 bg-primary" @click="loadMore">더보기</button>
            </div>
        </div>
    </div>
</template>
<script>
import Workers from "../../Components/Workers";
export default {
    components: {Workers},

    data() {
        return {
            workers: this.$page.props.workers,
            categories: this.$page.props.categories,
            form: this.$inertia.form({
                word: this.$page.props.word,
                orderBy: this.$page.props.orderBy,
                category_ids: this.$page.props.category_ids,
                page: 1
            }),
            loading: false,
        }
    },

    methods: {
        clearCategories(){
            this.form.category_ids = [];

            this.filter();
        },

        loadMore(){
            if(!this.loading){
                this.form.page += 1;

                this.filter();
            }
        },

        filter(){
            let isLoadMore = this.workers.meta.current_page !== this.form.page;

            this.loading = true;

            if(!isLoadMore)
                this.form.page = 1;

            this.form.get("/workers", {
                preserveScroll: true,
                preserveState: true,
                replace: true,
                immediate: true,
                onSuccess: (response) => {
                    this.loading = false;

                    if(isLoadMore) {
                        return this.workers = {
                            ...response.props.workers,
                            data: [...this.workers.data, ...response.props.workers.data]
                        }
                    }

                    return this.workers = response.props.workers;
                }
            });
        }
    },

    mounted() {

    }
}
</script>
LIST