表格耶!這幾個範例真的是蠻實用的!~
快學起來~看看這個表格會用到幾行程式碼就完成?
前端好好玩~ Grid with Sort and Filter
<!--
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>
這是一個示例,展示了如何創建一個可重用的表格組件並使用外部數據。
使用 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'。
開始模板區塊,用於定義組件的 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
來填充網格。用戶可以通過搜索框輸入文字,並根據輸入的關鍵字來過濾顯示的數據。
<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>
這段代碼展示了一個可過濾和排序的表格組件。以下是逐行解釋:
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 (升序)。
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>
<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>
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!