프로그래밍/VueJS

[vue.js] LIST 와 페이징 PAGING 이전, 다음 버튼

재우니 2024. 4. 24. 11:04

 

 

 

WEB API 는 무료 오픈 사이트인 "https://jsonplaceholder.typicode.com/posts" 를 활용하였습니다. 

 

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue.js Example with Server-Side Pagination</title>
    <!-- Include Vue.js, Axios, and Bootstrap CDN -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>

<body>

    <div id="app" class="container">
        <ul class="list-group">
            <li class="list-group-item" v-for="post in paginatedPosts" :key="post.id">
                {{ post.title }}
            </li>
        </ul>
        <ul class="pagination">
            <li><button class="btn btn-primary" @click="goToFirstPage">◀◀ 처음</button></li>
            <li><button class="btn btn-primary" @click="previousPageGroup" :disabled="pageGroup === 1">◀ 이전</button>
            </li>
            <li v-for="pageNumber in pageGroupNumbers" :key="pageNumber">
                <button class="btn btn-primary" @click="goToPage(pageNumber)" :disabled="currentPage === pageNumber">
                    {{ pageNumber }}
                </button>
            </li>
            <li><button class="btn btn-primary" @click="nextPageGroup"
                    :disabled="pageGroup * pageGroupSize >= totalPageNumbers">다음 ▶</button>
            <li><button class="btn btn-primary" @click="goToLastPage">마지막 ▶▶</button></li>
            </li>
        </ul>

    </div>

    <script>
        new Vue({
            el: '#app',
            data: {
                posts: [],
                pageSize: 12,
                currentPage: 1,
                totalCount: 0,
                pageGroup: 1,
                pageGroupSize: 10,
            },
            computed: {
                totalPageNumbers() {
                    return Math.ceil(this.totalCount / this.pageSize);
                },
                paginatedPosts() {
                    return this.posts;
                },
                pageGroupNumbers() {
                    let start = (this.pageGroup - 1) * this.pageGroupSize + 1;
                    let end = start + this.pageGroupSize;
                    let numbers = [];
                    for (let i = start; i < end; i++) {
                        if (i <= this.totalPageNumbers) {
                            numbers.push(i);
                        }
                    }
                    return numbers;
                },
            },
            methods: {
                fetchData(page) {
                    axios.get(`https://jsonplaceholder.typicode.com/posts?_page=${page}&_limit=${this.pageSize}`)
                        .then(response => {
                            this.posts = response.data;
                            this.totalCount = parseInt(response.headers['x-total-count']) || 0;
                        })
                        .catch(error => {
                            console.error('Error fetching data from API:', error);
                        });
                },
                goToPage(pageNumber) {
                    this.currentPage = pageNumber;
                    this.fetchData(pageNumber);
                },
                nextPageGroup() {
                    if (this.pageGroup * this.pageGroupSize < this.totalPageNumbers) {
                        this.pageGroup++;
                        this.goToPage((this.pageGroup - 1) * this.pageGroupSize + 1);
                    }
                },
                previousPageGroup() {
                    if (this.pageGroup > 1) {
                        this.pageGroup--;
                        this.goToPage((this.pageGroup - 1) * this.pageGroupSize + 1);
                    }
                },
                goToFirstPage() {
                    this.currentPage = 1;
                    this.pageGroup = 1;
                    this.fetchData(this.currentPage);
                },
                goToLastPage() {
                    this.currentPage = this.totalPageNumbers;
                    this.pageGroup = Math.ceil(this.totalPageNumbers / this.pageGroupSize);
                    this.fetchData(this.currentPage);
                },
            },
            mounted() {
                this.fetchData(this.currentPage);
            }
        });
    </script>


    <style>
        .pagination {
            list-style: none;
            display: flex;
            margin: 10px 0;
        }

        .pagination li {
            margin-right: 5px;
        }

        .pagination button {
            padding: 5px 10px;
        }
    </style>

</body>

</html>

 

 

실행한 화면

 

 

 

computed 설명


계산된 속성입니다. 이는 데이터를 변형하거나 가공하여 반환하는 함수와 같은 역할을 합니다. 계산된 속성은 종속된 데이터에 따라 결과를 캐싱합니다. 즉, 종속된 데이터가 변경되지 않은 상태에서 계산된 속성을 여러 번 호출하더라도, 첫 번째 실행 이후로는 캐시된 결과를 반환합니다. 이로 인해 불필요한 연산을 줄이고 성능을 향상시킬 수 있습니다. 계산된 속성은 get과 set 두 가지 메서드를 가질 수 있습니다. get은 계산된 속성을 읽을 때 실행되며, set은 계산된 속성에 값을 할당할 때 실행됩니다.

 

 

computed: {
    fullname: {
        get: function() {
            return this.firstname + ' ' + this.lastname;
        },
        set: function(newValue) {
            var names = newValue.split(' ');
            this.firstname = names[0];
            this.lastname = names[names.length - 1];
        }
    }
}

 

위의 코드에서 fullname은 get 메서드를 통해 firstname과 lastname을 합쳐 반환하고, set 메서드를 통해 fullname에 새 값을 할당할 때 이를 분리하여 firstname과 lastname에 할당합니다.

 

 

 

methods:

 

메서드를 정의하는 옵션입니다. 이는 컴포넌트에서 사용할 함수를 정의하는 곳입니다. 메서드는 호출될 때마다 실행되므로, 캐싱은 이루어지지 않습니다. 이는 사용자의 액션에 응답하거나, 반복적으로 사용하는 함수를 정의하는데 사용됩니다. 메서드는 계산된 속성과는 달리, 파라미터값을 받을 수 있습니다. 이를 통해 동적인 행동을 정의할 수 있습니다.

 

 

 

methods: {
    greet: function(time, name) {
        return 'Good ' + time + ', ' + name;
    }
}

 

 

위의 코드에서 greet 메서드는 time과 name 두 가지 인자를 받아 문자열을 반환합니다.

 

 

따라서, computed와 methods 중 어떤 것을 사용할지 결정할 때는,

연산 결과를 캐싱할 필요가 있거나 종속된 데이터에 따라 결과가 변하는 경우에는 computed

동적인 행동을 정의하거나 사용자의 액션에 응답해야 하는 경우에는 methods

사용하면 됩니다.

 

exam.html
0.00MB

 

 


 

이전, 다음 기능만 넣고자 한다면?

 

 

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue.js Simplified Pagination Example</title>
    <!-- Include Vue.js, Axios, and Bootstrap CDN -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>

<body>

    <div id="app" class="container">
        <ul class="list-group">
            <li class="list-group-item" v-for="post in posts" :key="post.id">
                {{ post.id }} {{ post.title }}
            </li>
        </ul>
        <div class="pagination">
            <button class="btn btn-primary" @click="previousPage" :disabled="currentPage === 1">이전</button>
            <button class="btn btn-primary" @click="nextPage" :disabled="currentPage >= totalPageNumbers">다음</button>
        </div>
    </div>

    <script>
        new Vue({
            el: '#app',
            data: {
                posts: [],
                pageSize: 5,
                currentPage: 1,
                totalCount: 0,
            },
            computed: {
                totalPageNumbers() {
                    return Math.ceil(this.totalCount / this.pageSize);
                },
            },
            methods: {
                fetchData(page) {                    
                    axios.get(`https://jsonplaceholder.typicode.com/posts?_page=${page}&_limit=${this.pageSize}`)
                        .then(response => {
                            this.posts = response.data;
                            this.totalCount = parseInt(response.headers['x-total-count']) || 0;
                        })
                        .catch(error => {
                            console.error('Error fetching data from API:', error);
                        });
                },
                previousPage() {
                    if (this.currentPage > 1) {
                        this.currentPage--;
                        this.fetchData(this.currentPage);
                    }
                },
                nextPage() {
                    if (this.currentPage < this.totalPageNumbers) {
                        this.currentPage++;
                        this.fetchData(this.currentPage);
                    }
                },
            },
            mounted() {
                console.log(this.currentPage);
                this.fetchData(this.currentPage);
            }
        });
    </script>

    <style>
        .pagination {
            display: flex;
            justify-content: center;
            margin: 10px 0;
        }
    </style>

</body>

</html>