表格耶!這幾個範例真的是蠻實用的!~
快學起來~看看這個表格會用到幾行程式碼就完成?
前端好好玩~ Grid with Sort and Filter
App.vue
<!--
An example of creating a reusable grid component and using it with external data.
-->
<script setup>
import DemoGrid from './Grid.vue'
import { ref } from 'vue'
const searchQuery = ref('')
const gridColumns = ['name', 'power']
const gridData = [
{ name: 'Chuck Norris', power: Infinity },
{ name: 'Bruce Lee', power: 9000 },
{ name: 'Jackie Chan', power: 7000 },
{ name: 'Jet Li', power: 8000 }
]
</script>
<template>
<form id="search">
Search <input name="query" v-model="searchQuery">
</form>
<DemoGrid
:data="gridData"
:columns="gridColumns"
:filter-key="searchQuery">
</DemoGrid>
</template>
這是一個示例,展示了如何創建一個可重用的表格組件並使用外部數據。
<script setup> 部分
使用 Vue 3 的 <script setup> 語法來簡化組件的定義和設置。
import DemoGrid from './Grid.vue'導入一個名為
DemoGrid 的網格組件,這個組件定義在 Grid.vue 文件中。import { ref } from 'vue'
從 Vue 中導入 ref 函數,ref 用於創建響應式的引用變數。
const searchQuery = ref('')
創建一個響應式變數 searchQuery,初始值為空字符串。這個變數將用來存儲用戶的搜索查詢。
const gridColumns = ['name', 'power']
定義一個數組 gridColumns,其中包含表格的列名,分別是 'name' 和 'power'。
const gridData = [
{ name: 'Chuck Norris', power: Infinity },
{ name: 'Bruce Lee', power: 9000 },
{ name: 'Jackie Chan', power: 7000 },
{ name: 'Jet Li', power: 8000 }
]
定義一個數組 gridData,其中包含要顯示在網格中的數據。每個數據項是一個物件,包含兩個屬性:'name' 和 'power'。
<template> 部分
開始模板區塊,用於定義組件的 HTML 結構。
<form id="search">
Search <input name="query" v-model="searchQuery">
</form>
創建一個帶有 ID 為 "search" 的表單,其中包含一個輸入框。輸入框的 v-model 綁定到 searchQuery,這樣當用戶輸入內容時,searchQuery 的值會自動更新。
<DemoGrid
:data="gridData"
:columns="gridColumns"
:filter-key="searchQuery">
</DemoGrid>
使用 DemoGrid 組件,並傳遞三個屬性:
data:傳遞gridData作為網格數據。columns:傳遞gridColumns作為網格列。filter-key:傳遞searchQuery作為過濾關鍵字。
這段代碼創建了一個簡單的應用,該應用展示了一個可重用的表格組件 DemoGrid,並使用外部數據 gridData 來填充網格。用戶可以通過搜索框輸入文字,並根據輸入的關鍵字來過濾顯示的數據。
Grid.vue
<script setup>
import { ref, computed } from 'vue'
const props = defineProps({
data: Array,
columns: Array,
filterKey: String
})
const sortKey = ref('')
const sortOrders = ref(
props.columns.reduce((o, key) => ((o[key] = 1), o), {})
)
const filteredData = computed(() => {
let { data, filterKey } = props
if (filterKey) {
filterKey = filterKey.toLowerCase()
data = data.filter((row) => {
return Object.keys(row).some((key) => {
return String(row[key]).toLowerCase().indexOf(filterKey) > -1
})
})
}
const key = sortKey.value
if (key) {
const order = sortOrders.value[key]
data = data.slice().sort((a, b) => {
a = a[key]
b = b[key]
return (a === b ? 0 : a > b ? 1 : -1) * order
})
}
return data
})
function sortBy(key) {
sortKey.value = key
sortOrders.value[key] *= -1
}
function capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1)
}
</script>
<template>
<table v-if="filteredData.length">
<thead>
<tr>
<th v-for="key in columns"
@click="sortBy(key)"
:class="{ active: sortKey == key }">
{{ capitalize(key) }}
<span class="arrow" :class="sortOrders[key] > 0 ? 'asc' : 'dsc'">
</span>
</th>
</tr>
</thead>
<tbody>
<tr v-for="entry in filteredData">
<td v-for="key in columns">
{{entry[key]}}
</td>
</tr>
</tbody>
</table>
<p v-else>No matches found.</p>
</template>
<style>
table {
border: 2px solid #42b983;
border-radius: 3px;
background-color: #fff;
}
th {
background-color: #42b983;
color: rgba(255, 255, 255, 0.66);
cursor: pointer;
user-select: none;
}
td {
background-color: #f9f9f9;
}
th,
td {
min-width: 120px;
padding: 10px 20px;
}
th.active {
color: #fff;
}
th.active .arrow {
opacity: 1;
}
.arrow {
display: inline-block;
vertical-align: middle;
width: 0;
height: 0;
margin-left: 5px;
opacity: 0.66;
}
.arrow.asc {
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-bottom: 4px solid #fff;
}
.arrow.dsc {
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 4px solid #fff;
}
</style>
這段代碼展示了一個可過濾和排序的表格組件。以下是逐行解釋:
<script setup> 部分
import { ref, computed } from 'vue'
從 Vue 中導入 ref 和 computed 函數,用於創建響應式變數和計算屬性。
const props = defineProps({
data: Array,
columns: Array,
filterKey: String
})
使用 defineProps 定義組件的 props,包括 data (數據數組),columns (列名數組),和 filterKey (過濾關鍵字)。
const sortKey = ref('')
創建一個響應式變數 sortKey,用來存儲當前的排序鍵,初始值為空字符串。
const sortOrders = ref(
props.columns.reduce((o, key) => ((o[key] = 1), o), {})
)
創建一個響應式變數 sortOrders,用來存儲每個列的排序順序。初始化時,使用 props.columns 中的每個列名將 sortOrders 設置為 1 (升序)。
Q: 什麼是reduce方法?
reduce 方法是一個用於累加數組中所有元素的高階函數。它會遍歷數組中的每一個元素,並將其累加到一個累加器(accumulator)中。這個累加器的初始值可以通過參數設定。 reduce 方法最終返回累加器的值。它通常用於需要從數組生成單個值(如總和、乘積、平均值、或轉換為另一種資料結構)的場合。
array.reduce(callback, initialValue)
callback: 在每個元素上執行的函數,接收四個參數:accumulator: 累加器,累積回調的返回值。currentValue: 當前正在處理的數組元素。currentIndex(可選): 當前正在處理的數組元素的索引。array(可選): 調用reduce的數組。
initialValue: 作為第一次調用callback時accumulator的值。如果未提供initialValue,將使用數組中的第一個元素,並從第二個元素開始迭代。
- 計算數組元素的總和
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
console.log(sum); // 15
- 將數組轉換為物件
假設我們有一個包含列名的數組,我們希望將其轉換為一個物件,並將每個列名的排序順序設為 1。
const columns = ['name', 'power'];
const sortOrders = columns.reduce((accumulator, key) => {
accumulator[key] = 1;
return accumulator;
}, {});
console.log(sortOrders); // { name: 1, power: 1 }
在這個範例中:
columns.reduce方法遍歷columns數組中的每一個元素。accumulator初始為空物件{}。- 對於數組中的每個
key,設置accumulator[key] = 1。 - 最終返回累加結果
accumulator,也就是{ name: 1, power: 1 }。
讓我們回到您的原始代碼:
const sortOrders = ref(
props.columns.reduce((o, key) => ((o[key] = 1), o), {})
);
props.columns是一個數組,包含列名。reduce方法遍歷props.columns中的每個元素(列名)。- 初始值
initialValue為空物件{}。 - 對於每個列名
key,執行(o[key] = 1),將key對應的值設為1。 - 返回累加結果
o,最終o變成{ name: 1, power: 1 }。 ref函數將生成的物件包裝成響應式的,存儲在sortOrders中。
這段代碼的作用是創建一個物件,其中包含列名作為鍵,並將每個鍵的值設置為初始排序順序(1 表示升序)。
const filteredData = computed(() => {
let { data, filterKey } = props
if (filterKey) {
filterKey = filterKey.toLowerCase()
data = data.filter((row) => {
return Object.keys(row).some((key) => {
return String(row[key]).toLowerCase().indexOf(filterKey) > -1
})
})
}
const key = sortKey.value
if (key) {
const order = sortOrders.value[key]
data = data.slice().sort((a, b) => {
a = a[key]
b = b[key]
return (a === b ? 0 : a > b ? 1 : -1) * order
})
}
return data
})
創建一個計算屬性 filteredData,用於根據 filterKey 過濾和根據 sortKey 排序數據:
- 如果
filterKey不為空,則將filterKey轉為小寫,並過濾data,只保留包含filterKey的行。 - 如果
sortKey不為空,則根據sortKey和sortOrders對數據進行排序。
function sortBy(key) {
sortKey.value = key
sortOrders.value[key] *= -1
}
定義 sortBy 函數,用於根據給定的鍵進行排序。點擊某列時,設置 sortKey 為該列,並反轉 sortOrders 中該列的排序順序。
function capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1)
}
定義 capitalize 函數,用於將字符串的首字母大寫。
<template> 部分
<template>
<table v-if="filteredData.length">
<thead>
<tr>
<th v-for="key in columns"
@click="sortBy(key)"
:class="{ active: sortKey == key }">
{{ capitalize(key) }}
<span class="arrow" :class="sortOrders[key] > 0 ? 'asc' : 'dsc'">
</span>
</th>
</tr>
</thead>
<tbody>
<tr v-for="entry in filteredData">
<td v-for="key in columns">
{{entry[key]}}
</td>
</tr>
</tbody>
</table>
<p v-else>No matches found.</p>
</template>
定義模板結構:
- 如果
filteredData不為空,則顯示一個表格: - 表頭 (
<thead>):使用v-for渲染每個列名,並設置@click事件以觸發sortBy函數。根據當前排序鍵設置class。 - 表身 (
<tbody>):使用v-for渲染每行數據,並在每行中使用v-for渲染每個列的數據。
- 表頭 (
- 如果
filteredData為空,則顯示 "No matches found." 提示。
<style> 部分
<style>
table {
border: 2px solid #42b983;
border-radius: 3px;
background-color: #fff;
}
th {
background-color: #42b983;
color: rgba(255, 255, 255, 0.66);
cursor: pointer;
user-select: none;
}
td {
background-color: #f9f9f9;
}
th,
td {
min-width: 120px;
padding: 10px 20px;
}
th.active {
color: #fff;
}
th.active .arrow {
opacity: 1;
}
.arrow {
display: inline-block;
vertical-align: middle;
width: 0;
height: 0;
margin-left: 5px;
opacity: 0.66;
}
.arrow.asc {
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-bottom: 4px solid #fff;
}
.arrow.dsc {
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 4px solid #fff;
}
</style>
定義表格的樣式:
- 設置表格邊框、背景顏色、圓角等樣式。
- 設置表頭和表格單元格的背景顏色、最小寬度、填充、字體顏色等樣式。
- 設置表頭在排序時的樣式,包括排序箭頭的樣式。

這一篇原來計算屬性是用在sort跟filter的地方,還需要多練習才能好好應用!
這樣以後寫好一次就可以重複使用這個表格摟~yeah!












