運用 Vue.js 前端框架,將發送到後端 API 請求的回傳 json 檔案,在頁面上做出分頁、搜尋表格的內容,而不用屢次變動資料就對後端發送請求。
實作需求
1.分頁表格元件 (component) 的資料由父層的頁面提供
2.分頁接收到父層的資料後,依序進行 methods, data 和 computed
3.用 watch 來監聽 data 內的變數是否有變化
常見問題
1. computed 與 method 的區別?
最大的區別為 computed 會將輸出的結果存下來,而 method 不會。
在以下例子中,頁碼是需要一直變化的,所以放在 methods 中。至於分頁需求要用來操作陣列的 pageStart, totalPage, filterRows,其結果是要存下來以供篩選和搜尋用的,所以用 computed。
methods 需要綁定事件來啟動,而 computed 是只要相關的值有變化就會重新計算。
2. props 的資料無法修改?
props 是屬於單向從父層到子層的傳遞,若需要對父層傳來的資料做操作(我們這邊要用 slice 來修改陣列),那麼可以新增一個變數來複製一份父層資料,然後回傳這個變數修改後的結果就好。
3. watch 的意義?
顧名思義就是監聽某個數值的變化。因為每次執行搜尋,需要將 data 內的 currentPage 變數修改回 1,這時就可以用 watch 來監聽 filterRows 的狀況。每當 filterRows 執行時,就將 this.currentPage = 1 。
程式碼展示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
// father.vue,將資料傳入 <template> <div class="container py-5"> <DataWithPagination :countries="countries" /> </div> </template> // children.vue <template> <div> <!--分頁部分--> <div class="row justify-content-center"> <nav aria-label="Page navigation example"> <ul class="pagination"> <li class="page-item" :class="['page-item',{disabled:currentPage===1}]" @click.prevent="setPage(currentPage-1)" > <a class="page-link" href="#"><</a> </li> <li v-for="page in totalPage" :key="page" class="page-item" :class="['page-item',{active:currentPage === page}]" @click.prevent="setPage(page)" > <a class="page-link" href="#">{{page}}</a> </li> <li class="page-item" :class="['page-item',{disabled:currentPage===totalPage}]" @click.prevent="setPage(currentPage+1)" > <a class="page-link" href="#">></a> </li> </ul> </nav> </div> <!--表格部分--> <table class="table table-hover"> <thead class="thead-dark"> <tr> <th scope="col">國家/區域</th> <th scope="col">類型</th> <th scope="col">天數</th> <th scope="col">備註</th> </tr> </thead> <tbody> <tr v-for="(country,index) in filterRows.slice(pageStart, pageStart + offset)" :key="index.id" > <td>{{country.name}}</td> <td>{{country.Category.name}}</td> <td>{{country.days}}</td> <td>{{country.remark}}</td> </tr> </tbody> </table> </div> </template> <script> export default { name: "DataWithPagination", props: { countries: { type: Array, required: true } }, data() { return { query: "", currentPage: 1, offset: 20 }; }, computed: { filterRows() { let query = this.query.toLowerCase(); let originData = this.countries; if (!this.query.match(/^[ ]*$/)) { return originData.filter(d => { return d.name.toLowerCase().indexOf(query) > -1; }); } else { return originData; } }, pageStart() { return (this.currentPage - 1) * this.offset; }, totalPage() { return Math.ceil(this.filterRows.length / this.offset); } }, methods: { setPage(idx) { if (idx <= 0 || idx > this.totalPage) { return; } this.currentPage = idx; } }, watch: { filterRows: { deep: true, handler: function() { this.currentPage = 1; } } } }; </script> |
參考資料
1. [VueJS-V2] 在 v-for 列表完成分頁功能
2. [VueJS-V2] 在 v-for 列表完成分頁功能 展示碼
3. [Vue學習筆記](七)計算屬性、監聽器、過濾器 — computed, watch,filter
4. Vue.js 09 – Watch
5. vue.js 中 data, prop, computed, method,watch 介紹
6. Handling unexpected side effect in computed properties – VueJS