MUKI AI Summary
JavaScript 和 CSS 框架常被用來加速網站開發,但不一定需要使用。Vue.js 可以不依賴 CSS 框架,自行實現表格和分頁功能。首先安裝 vue-router,設定路由。接著可使用假資料或 API 取得資料,並在表格中顯示第一頁內容。使用 vue-router 實現頁碼,透過 query 參數控制頁面顯示。監聽 route.query.page 變化,根據新頁碼更新資料。完整範例可在線上 DEMO 網址查看,提供了無需 CSS 框架的實作方式。...
前言
JavaScript 框架與 CSS 框架的相輔相成,為我們開發網站提供了許多便利性的幫助,但也許你偶爾會想著:「我們用 Vue.js 後,一定要使用對應的 CSS 框架才能做網站嗎?」
答案當然是否定的!畢竟 CSS 框架只是一個工具,他的優點是加速我們的設計與開發,但沒有了他,我們一樣能寫出具有特色的網站。
以我為例,我曾經用 Vue.js 寫一個網站後台,只用到 TailwindCSS,沒有用 Element Plus 這類的 CSS 框架,今天想跟大家分享的就是該網站的精華,第一篇就是如何自己寫出表格與分頁的功能。
步驟一:安裝 vue-router
首先,還是需要安裝 vue-router 套件,並且設定路由,這邊讓我們快速處理:
$ npm install vue-router@4
▼ 我建立了檔案 TablePagination.vue,並設定路由為 /tablepagination
import { createRouter, createWebHistory } from 'vue-router' const routes = [ { path: '/tablepagination', name: 'TablePagination', component: () => import('./views/TablePagination.vue') } ] const router = createRouter({ history: createWebHistory(), routes }) export default router
步驟二:取得資料(假資料或 API 皆可)
我這邊會用假資料為例,但不管你是想要測試,或是已經有現成的 API 資料可撈取,都可以用類似的方式做到。
▼ 我用亂數產生了一些資料,並且模擬 API 回傳的格式如下
<script setup lang="ts"> import { reactive } from 'vue' // 產生假資料 const randomData = (s: number, n: number) => { return Array.from({ length: n }, () => ({ id: s++, name: `MUKI_${s}`, age: Math.floor(Math.random() * 100) })) } // 模擬 API 回傳的資料格式,包含頁碼 const data = reactive({ pages: { limit: 12, total_page: 5, now_page: 1 }, details: randomData(0, 12) }) </script>
步驟三:在表格顯示第一頁的內容
▼ 在表格顯示 data.details
的資料,這是第一個客製化,用 <table>
標籤以及 v-for
語法就能做到。此外我用了 TailwindCSS 幫我快速處理樣式,如果你沒有用 TailwindCSS,可以把 class 內的資料改成你自己的設定
<table v-if="data.details.length > 0"> <thead> <tr class="text-left border-b border-gray-300"> <th class="w-28 py-1">ID</th> <th class="w-28 py-1">Name</th> <th class="w-28 py-1">Age</th> </tr> </thead> <tbody> <tr v-for="item in data.details" :key="item.id" :class="{ 'bg-gray-200': item.id % 2 === 1 }"> <td class="py-1">{{ item.id }}</td> <td class="py-1">{{ item.name }}</td> <td class="py-1">{{ item.age }}</td> </tr> </tbody> </table>
▼ 呈現在表格的樣子
步驟四:使用 vue-router 製作頁碼
▼ 先做好頁碼的樣式
<template> <ol v-if="data.pages.total_page > 1" class="flex mt-10"> <li class="px-4"> 第一頁 </li> <li v-for="item in data.pages.total_page" :key="item" class="px-4" :class="{ current: item === current }"> {{ item }} </li> <li class="px-4"> 最後一頁 </li> </ol> </template> <style lang="postcss" scoped> .current { @apply rounded-lg text-white bg-orange-500; } </style>
▼ 這個頁碼有「第一頁」以及「最後一頁」,另外會根據 data
裡的 total_page
顯示所有的頁碼
接著,我們可以使用 <router-link>
的 qeury
帶入參數 page
以及頁碼 (1, 2, 3, 4...),query
同時會更改網址;舉例來說:如果想分享第二頁的內容,就能直接複製網址,對方貼上後,會跳到第二頁並顯示該內容。
▼ 切到第二頁,網址也會跟著改變
▼ 使用 <router-link>
的 query
製作該功能
<!-- 第一頁是固定的參數,所以 page 帶 1 --> <router-link :to="{ query: { page: 1 } }">第一頁</router-link> <!-- 根據 total_page 跑迴圈的頁碼,page 帶 item 變數 --> <li v-for="item in data.pages.total_page" :key="item" class="px-4" :class="{ current: item === current }"> <router-link :to="{ query: { page: item } }">{{ item }}</router-link> </li> <!-- 最後一頁是總頁數,page 帶 total_page --> <router-link :to="{ query: { page: data.pages.total_page } }">最後一頁</router-link>
▼ 再來監聽 route.query.page
的變化,根據新頁碼帶對應的 API 資料,但我沒有串 API,所以用模擬資料的函式 randomData()
,抓新的資料至 data.details
<script setup lang="ts"> import { watch } from 'vue' watch(() => route.query.page, (newPage) => { /* route.query.page 變化時,current 的值也會跟著改變,讓當前頁有不同的樣式 */ current.value = Number(newPage) || 1 data.details = randomData(0, 12) }) </script>
完整範例
▼ 完整的 TablePagination.vue
<template> <table v-if="data.details.length > 0"> <thead> <tr class="text-left border-b border-gray-300"> <th class="w-28 py-1">ID</th> <th class="w-28 py-1">Name</th> <th class="w-28 py-1">Age</th> </tr> </thead> <tbody> <tr v-for="item in data.details" :key="item.id" :class="{ 'bg-gray-200': item.id % 2 === 1 }" > <td class="py-1">{{ item.id }}</td> <td class="py-1">{{ item.name }}</td> <td class="py-1">{{ item.age }}</td> </tr> </tbody> </table> <ol v-if="data.pages.total_page > 1" class="flex mt-10"> <li class="px-4"> <router-link :to="{ query: { page: 1 } }">第一頁</router-link> </li> <li v-for="item in data.pages.total_page" :key="item" class="px-4" :class="{ current: item === current }" > <router-link :to="{ query: { page: item } }">{{ item }}</router-link> </li> <li class="px-4"> <router-link :to="{ query: { page: data.pages.total_page } }">最後一頁</router-link> </li> </ol> </template> <script setup lang="ts"> import { ref, reactive, onMounted, watch } from 'vue' import { useRoute } from 'vue-router' const current = ref(1) const route = useRoute() const randomData = (s: number, n: number) => { return Array.from({ length: n }, () => ({ id: s++, name: `MUKI_${s}`, age: Math.floor(Math.random() * 100) })) } const data = reactive({ pages: { limit: 12, total_page: 5, now_page: 1 }, details: randomData(0, 12) }) onMounted(() => { current.value = Number(route.query.page) || 1 }) watch( () => route.query.page, (newPage) => { current.value = Number(newPage) || 1 data.details = randomData(0, 12) } ) </script> <style lang="postcss" scoped> .current { @apply rounded-lg text-white bg-orange-500; } </style>
➩➩ 線上 DEMO 網址: https://lfdt4x-5173.csb.app/tablepagination?page=1
▼ codesandbox 範例