DataTable 以表格格式顯示資料。
import DataTable from 'primevue/datatable';
import Column from 'primevue/column';
import ColumnGroup from 'primevue/columngroup'; // optional
import Row from 'primevue/row'; // optional
DataTable 需要一個 value 作為要顯示的資料,以及 Column 元件作為表示的子項。
<DataTable :value="products" tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
欄位可以透過程式設計方式建立。
<DataTable :value="products" tableStyle="min-width: 50rem">
<Column v-for="col of columns" :key="col.field" :field="col.field" :header="col.header"></Column>
</DataTable>
透過範本支援在 header 和 footer 區段的自訂內容。
<DataTable :value="products" tableStyle="min-width: 50rem">
<template #header>
<div class="flex flex-wrap items-center justify-between gap-2">
<span class="text-xl font-bold">Products</span>
<Button icon="pi pi-refresh" rounded raised />
</div>
</template>
<Column field="name" header="Name"></Column>
<Column header="Image">
<template #body="slotProps">
<img :src="`https://primefaces.org/cdn/primevue/images/product/${slotProps.data.image}`" :alt="slotProps.data.image" class="w-24 rounded" />
</template>
</Column>
<Column field="price" header="Price">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.price) }}
</template>
</Column>
<Column field="category" header="Category"></Column>
<Column field="rating" header="Reviews">
<template #body="slotProps">
<Rating :modelValue="slotProps.data.rating" readonly />
</template>
</Column>
<Column header="Status">
<template #body="slotProps">
<Tag :value="slotProps.data.inventoryStatus" :severity="getSeverity(slotProps.data)" />
</template>
</Column>
<template #footer> In total there are {{ products ? products.length : 0 }} products. </template>
</DataTable>
除了常規表格外,還有其他尺寸的替代方案可用。
<SelectButton v-model="size" :options="sizeOptions" optionLabel="label" dataKey="label" />
<DataTable :value="products" :size="size.value" tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
啟用 showGridlines 會顯示儲存格之間的邊框。
<DataTable :value="products" showGridlines tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
當存在 stripedRows 屬性時,會顯示交替的行。
<DataTable :value="products" stripedRows tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
透過新增 paginator 屬性並定義每頁 rows 來啟用分頁。
<DataTable :value="customers" paginator :rows="5" :rowsPerPageOptions="[5, 10, 20, 50]" tableStyle="min-width: 50rem">
<Column field="name" header="Name" style="width: 25%"></Column>
<Column field="country.name" header="Country" style="width: 25%"></Column>
<Column field="company" header="Company" style="width: 25%"></Column>
<Column field="representative.name" header="Representative" style="width: 25%"></Column>
</DataTable>
分頁器 UI 是使用 paginatorTemplate 屬性來自訂。每個元素都可以使用您自己的 UI 進行進一步自訂以取代預設 UI,請參閱 Paginator 元件以取得有關進階自訂選項的更多資訊。
<DataTable :value="customers" paginator :rows="5" :rowsPerPageOptions="[5, 10, 20, 50]" tableStyle="min-width: 50rem"
paginatorTemplate="RowsPerPageDropdown FirstPageLink PrevPageLink CurrentPageReport NextPageLink LastPageLink"
currentPageReportTemplate="{first} to {last} of {totalRecords}">
<template #paginatorstart>
<Button type="button" icon="pi pi-refresh" text />
</template>
<template #paginatorend>
<Button type="button" icon="pi pi-download" text />
</template>
<Column field="name" header="Name" style="width: 25%"></Column>
<Column field="country.name" header="Country" style="width: 25%"></Column>
<Column field="company" header="Company" style="width: 25%"></Column>
<Column field="representative.name" header="Representative" style="width: 25%"></Column>
</DataTable>
透過使用 paginatorcontainer 啟用分頁的無頭模式。
<DataTable :value="customers" paginator :rows="5" :rowsPerPageOptions="[5, 10, 20, 50]" tableStyle="min-width: 50rem">
<Column field="name" header="Name" style="width: 25%"></Column>
<Column field="country.name" header="Country" style="width: 25%"></Column>
<Column field="company" header="Company" style="width: 25%"></Column>
<Column field="representative.name" header="Representative" style="width: 25%"></Column>
<template #paginatorcontainer="{ first, last, page, pageCount, prevPageCallback, nextPageCallback, totalRecords }">
<div class="flex items-center gap-4 border border-primary bg-transparent rounded-full w-full py-1 px-2 justify-between">
<Button icon="pi pi-chevron-left" rounded text @click="prevPageCallback" :disabled="page === 0" />
<div class="text-color font-medium">
<span class="hidden sm:block">Showing {{ first }} to {{ last }} of {{ totalRecords }}</span>
<span class="block sm:hidden">Page {{ page + 1 }} of {{ pageCount }}</span>
</div>
<Button icon="pi pi-chevron-right" rounded text @click="nextPageCallback" :disabled="page === pageCount - 1" />
</div>
</template>
</DataTable>
透過新增 sortable 屬性啟用欄位的排序功能。
<DataTable :value="products" tableStyle="min-width: 50rem">
<Column field="code" header="Code" sortable style="width: 25%"></Column>
<Column field="name" header="Name" sortable style="width: 25%"></Column>
<Column field="category" header="Category" sortable style="width: 25%"></Column>
<Column field="quantity" header="Quantity" sortable style="width: 25%"></Column>
</DataTable>
可以透過將 sortMode 定義為 multiple 來排序多欄。此模式需要在按一下標題時按下 metaKey(例如 ⌘)。
<DataTable :value="products" sortMode="multiple" tableStyle="min-width: 50rem">
<Column field="code" header="Code" sortable style="width: 25%"></Column>
<Column field="name" header="Name" sortable style="width: 25%"></Column>
<Column field="category" header="Category" sortable style="width: 25%"></Column>
<Column field="quantity" header="Quantity" sortable style="width: 25%"></Column>
</DataTable>
定義預設的 sortField 和 sortOrder 會在單欄排序中以最初排序的方式顯示資料。在 multiple 排序模式中,應改為使用 multiSortMeta,並提供 DataTableSortMeta 物件的陣列。
<DataTable :value="products" sortField="price" :sortOrder="-1" tableStyle="min-width: 50rem">
<Column field="code" header="Code" sortable style="width: 20%"></Column>
<Column field="name" header="Name" sortable style="width: 20%"></Column>
<Column field="price" header="Price" :sortable="true">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.price) }}
</template>
</Column>
<Column field="category" header="Category" sortable style="width: 20%"></Column>
<Column field="quantity" header="Quantity" sortable style="width: 20%"></Column>
</DataTable>
當存在 removableSort 時,第三次點擊會從欄位中移除排序。
<DataTable :value="products" removableSort tableStyle="min-width: 50rem">
<Column field="code" header="Code" sortable style="width: 25%"></Column>
<Column field="name" header="Name" sortable style="width: 25%"></Column>
<Column field="category" header="Category" sortable style="width: 25%"></Column>
<Column field="quantity" header="Quantity" sortable style="width: 25%"></Column>
</DataTable>
透過定義參考 DataTableFilterMeta 執行個體的 filters 模型,以及使用 filter 範本為欄位指定篩選元素來啟用資料篩選。此範本會接收 filterModel 和 filterCallback 來建立您自己的 UI。
可選的全域篩選會根據綁定至 filters 物件 global 鍵的單一值搜尋資料。要搜尋的欄位是使用 globalFilterFields 定義。
<DataTable v-model:filters="filters" :value="customers" paginator :rows="10" dataKey="id" filterDisplay="row" :loading="loading"
:globalFilterFields="['name', 'country.name', 'representative.name', 'status']">
<template #header>
<div class="flex justify-end">
<IconField>
<InputIcon>
<i class="pi pi-search" />
</InputIcon>
<InputText v-model="filters['global'].value" placeholder="Keyword Search" />
</IconField>
</div>
</template>
<template #empty> No customers found. </template>
<template #loading> Loading customers data. Please wait. </template>
<Column field="name" header="Name" style="min-width: 12rem">
<template #body="{ data }">
{{ data.name }}
</template>
<template #filter="{ filterModel, filterCallback }">
<InputText v-model="filterModel.value" type="text" @input="filterCallback()" placeholder="Search by name" />
</template>
</Column>
<Column header="Country" filterField="country.name" style="min-width: 12rem">
<template #body="{ data }">
<div class="flex items-center gap-2">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${data.country.code}`" style="width: 24px" />
<span>{{ data.country.name }}</span>
</div>
</template>
<template #filter="{ filterModel, filterCallback }">
<InputText v-model="filterModel.value" type="text" @input="filterCallback()" placeholder="Search by country" />
</template>
</Column>
<Column header="Agent" filterField="representative" :showFilterMenu="false" style="min-width: 14rem">
<template #body="{ data }">
<div class="flex items-center gap-2">
<img :alt="data.representative.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${data.representative.image}`" style="width: 32px" />
<span>{{ data.representative.name }}</span>
</div>
</template>
<template #filter="{ filterModel, filterCallback }">
<MultiSelect v-model="filterModel.value" @change="filterCallback()" :options="representatives" optionLabel="name" placeholder="Any" style="min-width: 14rem" :maxSelectedLabels="1">
<template #option="slotProps">
<div class="flex items-center gap-2">
<img :alt="slotProps.option.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${slotProps.option.image}`" style="width: 32px" />
<span>{{ slotProps.option.name }}</span>
</div>
</template>
</MultiSelect>
</template>
</Column>
<Column field="status" header="Status" :showFilterMenu="false" style="min-width: 12rem">
<template #body="{ data }">
<Tag :value="data.status" :severity="getSeverity(data.status)" />
</template>
<template #filter="{ filterModel, filterCallback }">
<Select v-model="filterModel.value" @change="filterCallback()" :options="statuses" placeholder="Select One" style="min-width: 12rem" :showClear="true">
<template #option="slotProps">
<Tag :value="slotProps.option" :severity="getSeverity(slotProps.option)" />
</template>
</Select>
</template>
</Column>
<Column field="verified" header="Verified" dataType="boolean" style="min-width: 6rem">
<template #body="{ data }">
<i class="pi" :class="{ 'pi-check-circle text-green-500': data.verified, 'pi-times-circle text-red-400': !data.verified }"></i>
</template>
<template #filter="{ filterModel, filterCallback }">
<Checkbox v-model="filterModel.value" :indeterminate="filterModel.value === null" binary @change="filterCallback()" />
</template>
</Column>
</DataTable>
當 filterDisplay 設定為 menu 時,篩選 UI 會放置在彈出視窗內,並支援多個約束和進階範本。
<DataTable v-model:filters="filters" :value="customers" paginator showGridlines :rows="10" dataKey="id"
filterDisplay="menu" :loading="loading" :globalFilterFields="['name', 'country.name', 'representative.name', 'balance', 'status']">
<template #header>
<div class="flex justify-between">
<Button type="button" icon="pi pi-filter-slash" label="Clear" outlined @click="clearFilter()" />
<IconField>
<InputIcon>
<i class="pi pi-search" />
</InputIcon>
<InputText v-model="filters['global'].value" placeholder="Keyword Search" />
</IconField>
</div>
</template>
<template #empty> No customers found. </template>
<template #loading> Loading customers data. Please wait. </template>
<Column field="name" header="Name" style="min-width: 12rem">
<template #body="{ data }">
{{ data.name }}
</template>
<template #filter="{ filterModel }">
<InputText v-model="filterModel.value" type="text" placeholder="Search by name" />
</template>
</Column>
<Column header="Country" filterField="country.name" style="min-width: 12rem">
<template #body="{ data }">
<div class="flex items-center gap-2">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${data.country.code}`" style="width: 24px" />
<span>{{ data.country.name }}</span>
</div>
</template>
<template #filter="{ filterModel }">
<InputText v-model="filterModel.value" type="text" placeholder="Search by country" />
</template>
<template #filterclear="{ filterCallback }">
<Button type="button" icon="pi pi-times" @click="filterCallback()" severity="secondary"></Button>
</template>
<template #filterapply="{ filterCallback }">
<Button type="button" icon="pi pi-check" @click="filterCallback()" severity="success"></Button>
</template>
<template #filterfooter>
<div class="px-4 pt-0 pb-4 text-center">Customized Buttons</div>
</template>
</Column>
<Column header="Agent" filterField="representative" :showFilterMatchModes="false" :filterMenuStyle="{ width: '14rem' }" style="min-width: 14rem">
<template #body="{ data }">
<div class="flex items-center gap-2">
<img :alt="data.representative.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${data.representative.image}`" style="width: 32px" />
<span>{{ data.representative.name }}</span>
</div>
</template>
<template #filter="{ filterModel }">
<MultiSelect v-model="filterModel.value" :options="representatives" optionLabel="name" placeholder="Any">
<template #option="slotProps">
<div class="flex items-center gap-2">
<img :alt="slotProps.option.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${slotProps.option.image}`" style="width: 32px" />
<span>{{ slotProps.option.name }}</span>
</div>
</template>
</MultiSelect>
</template>
</Column>
<Column header="Date" filterField="date" dataType="date" style="min-width: 10rem">
<template #body="{ data }">
{{ formatDate(data.date) }}
</template>
<template #filter="{ filterModel }">
<DatePicker v-model="filterModel.value" dateFormat="mm/dd/yy" placeholder="mm/dd/yyyy" />
</template>
</Column>
<Column header="Balance" filterField="balance" dataType="numeric" style="min-width: 10rem">
<template #body="{ data }">
{{ formatCurrency(data.balance) }}
</template>
<template #filter="{ filterModel }">
<InputNumber v-model="filterModel.value" mode="currency" currency="USD" locale="en-US" />
</template>
</Column>
<Column header="Status" field="status" :filterMenuStyle="{ width: '14rem' }" style="min-width: 12rem">
<template #body="{ data }">
<Tag :value="data.status" :severity="getSeverity(data.status)" />
</template>
<template #filter="{ filterModel }">
<Select v-model="filterModel.value" :options="statuses" placeholder="Select One" showClear>
<template #option="slotProps">
<Tag :value="slotProps.option" :severity="getSeverity(slotProps.option)" />
</template>
</Select>
</template>
</Column>
<Column field="activity" header="Activity" :showFilterMatchModes="false" style="min-width: 12rem">
<template #body="{ data }">
<ProgressBar :value="data.activity" :showValue="false" style="height: 6px"></ProgressBar>
</template>
<template #filter="{ filterModel }">
<Slider v-model="filterModel.value" range class="m-4"></Slider>
<div class="flex items-center justify-between px-2">
<span>{{ filterModel.value ? filterModel.value[0] : 0 }}</span>
<span>{{ filterModel.value ? filterModel.value[1] : 100 }}</span>
</div>
</template>
</Column>
<Column field="verified" header="Verified" dataType="boolean" bodyClass="text-center" style="min-width: 8rem">
<template #body="{ data }">
<i class="pi" :class="{ 'pi-check-circle text-green-500 ': data.verified, 'pi-times-circle text-red-500': !data.verified }"></i>
</template>
<template #filter="{ filterModel }">
<label for="verified-filter" class="font-bold"> Verified </label>
<Checkbox v-model="filterModel.value" :indeterminate="filterModel.value === null" binary inputId="verified-filter" />
</template>
</Column>
</DataTable>
透過將 selectionMode 定義為 single 以及使用 selection 屬性進行值繫結來啟用單列選取。如果可用,建議使用 dataKey 為列提供唯一的識別碼,以最佳化效能。
預設情況下,需要按下 metaKey(例如 ⌘)才能取消選取列,但是可以透過停用 metaKeySelection 屬性來設定此行為。在啟用觸控的裝置中,此選項沒有任何作用,且行為與設定為 false 時相同。
<ToggleSwitch v-model="metaKey" inputId="input-metakey" />
<DataTable v-model:selection="selectedProduct" :value="products" selectionMode="single" :metaKeySelection="metaKey" dataKey="id" tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
可以透過將 selectionMode 設定為 multiple 來選取多列。預設情況下,在多重選取模式中,不需要按下 metaKey(例如 ⌘)來新增至現有的選取範圍。當存在可選的 metaKeySelection 時,行為會以需要按下 meta 鍵才能選取新列的方式變更。請注意,在啟用觸控的裝置中,DataTable 一律會忽略 metaKey。
<ToggleSwitch v-model="metaKey" inputId="input-metakey" />
<DataTable v-model:selection="selectedProduct" :value="products" selectionMode="multiple" :metaKeySelection="metaKey" dataKey="id" tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
在 Column 上將 selectionMode 指定為 single,會在該欄位內顯示一個單選按鈕以供選取。預設情況下,列點擊也會觸發選取,將 DataTable 的 selectionMode 設定為 radiobutton 以僅使用單選按鈕觸發選取。
<DataTable v-model:selection="selectedProduct" :value="products" dataKey="id" tableStyle="min-width: 50rem">
<Column selectionMode="single" headerStyle="width: 3rem"></Column>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
在 Column 上將 selectionMode 指定為 multiple,會在該欄位內顯示一個核取方塊以供選取。
標題核取方塊預設會切換整個資料集的選取狀態,當啟用分頁器時,您可以新增 selectAll 屬性和 select-all-change 事件,以僅控制可見列的選取狀態。
<DataTable v-model:selection="selectedProduct" :value="products" dataKey="id" tableStyle="min-width: 50rem">
<Column selectionMode="multiple" headerStyle="width: 3rem"></Column>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
在欄位內使用元素的列選取是透過範本來實作。
<DataTable :value="products" tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
<Column class="w-24 !text-end">
<template #body="{ data }">
<Button icon="pi pi-search" @click="selectRow(data)" severity="secondary" rounded></Button>
</template>
</Column>
</DataTable>
DataTable 提供 row-select 和 row-unselect 事件來監聽選取事件。
<DataTable v-model:selection="selectedProduct" :value="products" selectionMode="single" dataKey="id" :metaKeySelection="false"
@rowSelect="onRowSelect" @rowUnselect="onRowUnselect" tableStyle="min-width: 50rem">
<Column selectionMode="single" headerStyle="width: 3rem"></Column>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
列展開是使用 expandedRows 屬性來控制。具有展開器元素的欄位需要啟用 expander 屬性。可選的 rowExpand 和 rowCollapse 事件可用作回呼。
展開的列可以是列資料的陣列,或是當存在 dataKey 時,其鍵是參考列資料識別碼的字串,值是表示展開狀態的布林值的物件,例如 {'1004': true}。dataKey 替代方案對於大量資料而言效能更高。
<DataTable v-model:expandedRows="expandedRows" :value="products" dataKey="id"
@rowExpand="onRowExpand" @rowCollapse="onRowCollapse" tableStyle="min-width: 60rem">
<template #header>
<div class="flex flex-wrap justify-end gap-2">
<Button text icon="pi pi-plus" label="Expand All" @click="expandAll" />
<Button text icon="pi pi-minus" label="Collapse All" @click="collapseAll" />
</div>
</template>
<Column expander style="width: 5rem" />
<Column field="name" header="Name"></Column>
<Column header="Image">
<template #body="slotProps">
<img :src="`https://primefaces.org/cdn/primevue/images/product/${slotProps.data.image}`" :alt="slotProps.data.image" class="shadow-lg" width="64" />
</template>
</Column>
<Column field="price" header="Price">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.price) }}
</template>
</Column>
<Column field="category" header="Category"></Column>
<Column field="rating" header="Reviews">
<template #body="slotProps">
<Rating :modelValue="slotProps.data.rating" readonly />
</template>
</Column>
<Column header="Status">
<template #body="slotProps">
<Tag :value="slotProps.data.inventoryStatus" :severity="getSeverity(slotProps.data)" />
</template>
</Column>
<template #expansion="slotProps">
<div class="p-4">
<h5>Orders for {{ slotProps.data.name }}</h5>
<DataTable :value="slotProps.data.orders">
<Column field="id" header="Id" sortable></Column>
<Column field="customer" header="Customer" sortable></Column>
<Column field="date" header="Date" sortable></Column>
<Column field="amount" header="Amount" sortable>
<template #body="slotProps">
{{ formatCurrency(slotProps.data.amount) }}
</template>
</Column>
<Column field="status" header="Status" sortable>
<template #body="slotProps">
<Tag :value="slotProps.data.status.toLowerCase()" :severity="getOrderSeverity(slotProps.data)" />
</template>
</Column>
<Column headerStyle="width:4rem">
<template #body>
<Button icon="pi pi-search" />
</template>
</Column>
</DataTable>
</div>
</template>
</DataTable>
透過將 editMode 設定為 cell、使用 Column 的 editor 範本定義輸入元素,以及實作 cell-edit-complete 來更新狀態,來啟用儲存格編輯功能。
<DataTable :value="products" editMode="cell" @cell-edit-complete="onCellEditComplete"
:pt="{
table: { style: 'min-width: 50rem' },
column: {
bodycell: ({ state }) => ({
class: [{ '!py-0': state['d_editing'] }]
})
}
}"
>
<Column v-for="col of columns" :key="col.field" :field="col.field" :header="col.header" style="width: 25%">
<template #body="{ data, field }">
{{ field === 'price' ? formatCurrency(data[field]) : data[field] }}
</template>
<template #editor="{ data, field }">
<template v-if="field !== 'price'">
<InputText v-model="data[field]" autofocus fluid />
</template>
<template v-else>
<InputNumber v-model="data[field]" mode="currency" currency="USD" locale="en-US" autofocus fluid />
</template>
</template>
</Column>
</DataTable>
透過將 editMode 設定為 row 並使用 v-model 指示詞定義 editingRows 來保留編輯列的參考,來設定列編輯功能。與儲存格編輯模式類似,定義 Column 的 editor 插槽中的輸入元素,並實作 row-edit-save 以更新狀態是必要的。控制編輯狀態的欄位應套用 editor 範本。
<DataTable v-model:editingRows="editingRows" :value="products" editMode="row" dataKey="id" @row-edit-save="onRowEditSave"
:pt="{
table: { style: 'min-width: 50rem' },
column: {
bodycell: ({ state }) => ({
style: state['d_editing']&&'padding-top: 0.75rem; padding-bottom: 0.75rem'
})
}
}"
>
<Column field="code" header="Code" style="width: 20%">
<template #editor="{ data, field }">
<InputText v-model="data[field]" />
</template>
</Column>
<Column field="name" header="Name" style="width: 20%">
<template #editor="{ data, field }">
<InputText v-model="data[field]" fluid />
</template>
</Column>
<Column field="inventoryStatus" header="Status" style="width: 20%">
<template #editor="{ data, field }">
<Select v-model="data[field]" :options="statuses" optionLabel="label" optionValue="value" placeholder="Select a Status" fluid>
<template #option="slotProps">
<Tag :value="slotProps.option.value" :severity="getStatusLabel(slotProps.option.value)" />
</template>
</Select>
</template>
<template #body="slotProps">
<Tag :value="slotProps.data.inventoryStatus" :severity="getStatusLabel(slotProps.data.inventoryStatus)" />
</template>
</Column>
<Column field="price" header="Price" style="width: 20%">
<template #body="{ data, field }">
{{ formatCurrency(data[field]) }}
</template>
<template #editor="{ data, field }">
<InputNumber v-model="data[field]" mode="currency" currency="USD" locale="en-US" fluid />
</template>
</Column>
<Column :rowEditor="true" style="width: 10%; min-width: 8rem" bodyStyle="text-align:center"></Column>
</DataTable>
新增 scrollable 屬性以及資料檢視區的 scrollHeight 可啟用固定標題的垂直捲動。
<DataTable :value="customers" scrollable scrollHeight="400px" tableStyle="min-width: 50rem">
<Column field="name" header="Name"></Column>
<Column field="country.name" header="Country"></Column>
<Column field="representative.name" header="Representative"></Column>
<Column field="company" header="Company"></Column>
</DataTable>
彈性捲動功能會讓可捲動的檢視區區段變為動態,而不是固定值,以便它可以根據表格的父層大小成長或縮小。按一下下方的按鈕以顯示最大化的對話框,其中資料檢視區會根據大小變更自行調整。
<Button label="Show" icon="pi pi-external-link" @click="dialogVisible = true" />
<Dialog v-model:visible="dialogVisible" header="Flex Scroll" :style="{ width: '75vw' }" maximizable modal :contentStyle="{ height: '300px' }">
<DataTable :value="customers" scrollable scrollHeight="flex" tableStyle="min-width: 50rem">
<Column field="name" header="Name"></Column>
<Column field="country.name" header="Country"></Column>
<Column field="representative.name" header="Representative"></Column>
<Column field="company" header="Company"></Column>
</DataTable>
<template #footer>
<Button label="Ok" icon="pi pi-check" @click="dialogVisible = false" />
</template>
</Dialog>
當表格寬度超過父層寬度時,會顯示水平捲軸。
<DataTable :value="customers" scrollable scrollHeight="400px">
<Column field="id" header="Id" footer="Id" style="min-width: 100px"></Column>
<Column field="name" header="Name" footer="Name" style="min-width: 200px"></Column>
<Column field="country.name" header="Country" footer="Country" style="min-width: 200px"></Column>
<Column field="date" header="Date" footer="Date" style="min-width: 200px"></Column>
<Column field="balance" header="Balance" footer="Balance" style="min-width: 200px">
<template #body="{ data }">
{{ formatCurrency(data.balance) }}
</template>
</Column>
<Column field="company" header="Company" footer="Company" style="min-width: 200px"></Column>
<Column field="status" header="Status" footer="Status" style="min-width: 200px"></Column>
<Column field="activity" header="Activity" footer="Activity" style="min-width: 200px"></Column>
<Column field="representative.name" header="Representative" footer="Representative" style="min-width: 200px"></Column>
</DataTable>
透過啟用 frozenValue 屬性,可以在捲動期間固定列。
<DataTable
:value="customers"
:frozenValue="lockedCustomers"
scrollable
scrollHeight="400px"
:pt="{
table: { style: 'min-width: 50rem' },
bodyrow: ({ props }) => ({
class: [{ 'font-bold': props.frozenRow }]
})
}"
>
<Column field="name" header="Name"></Column>
<Column field="country.name" header="Country"></Column>
<Column field="representative.name" header="Representative"></Column>
<Column field="status" header="Status"></Column>
<Column style="flex: 0 0 4rem">
<template #body="{ data, frozenRow, index }">
<Button type="button" :icon="frozenRow ? 'pi pi-lock-open' : 'pi pi-lock'" :disabled="frozenRow ? false : lockedCustomers.length >= 2" text size="small" @click="toggleLock(data, frozenRow, index)" />
</template>
</Column>
</DataTable>
透過啟用 frozen 屬性,可以在水平捲動期間固定欄位。位置是使用可以是 left 或 right 的 alignFrozen 來定義。
<ToggleButton v-model="balanceFrozen" onIcon="pi pi-lock" offIcon="pi pi-lock-open" onLabel="Balance" offLabel="Balance" />
<DataTable :value="customers" scrollable scrollHeight="400px" class="mt-6">
<Column field="name" header="Name" style="min-width: 200px" frozen class="font-bold"></Column>
<Column field="id" header="Id" style="min-width: 100px"></Column>
<Column field="name" header="Name" style="min-width: 200px"></Column>
<Column field="country.name" header="Country" style="min-width: 200px"></Column>
<Column field="date" header="Date" style="min-width: 200px"></Column>
<Column field="company" header="Company" style="min-width: 200px"></Column>
<Column field="status" header="Status" style="min-width: 200px"></Column>
<Column field="activity" header="Activity" style="min-width: 200px"></Column>
<Column field="representative.name" header="Representative" style="min-width: 200px"></Column>
<Column field="balance" header="Balance" style="min-width: 200px" alignFrozen="right" :frozen="balanceFrozen">
<template #body="{ data }">
<span class="font-bold">{{ formatCurrency(data.balance) }}</span>
</template>
</Column>
</DataTable>
虛擬捲動是呈現大量資料的有效方式。其用法與一般捲動類似,但新增了 virtualScrollerOptions 屬性以定義固定 itemSize。在內部會使用 VirtualScroller 元件,因此請參閱 VirtualScroller 的 API 以取得有關可用選項的更多資訊。
在此範例中,表格會呈現 100000 個預先載入的記錄。
<DataTable :value="cars" scrollable scrollHeight="400px" :virtualScrollerOptions="{ itemSize: 46 }" tableStyle="min-width: 50rem">
<Column field="id" header="Id" style="width: 20%"></Column>
<Column field="vin" header="Vin" style="width: 20%"></Column>
<Column field="year" header="Year" style="width: 20%"></Column>
<Column field="brand" header="Brand" style="width: 20%"></Column>
<Column field="color" header="Color" style="width: 20%"></Column>
</DataTable>
當透過 virtualScrollerOptions 啟用延遲載入時,資料會在捲動期間依需求擷取,而不是預先載入。
在以下範例中,會使用記憶體內清單和逾時來模擬從遠端資料來源擷取。virtualCars 是一個空陣列,會在捲動時填入。
<DataTable :value="virtualCars" scrollable scrollHeight="400px" tableStyle="min-width: 50rem"
:virtualScrollerOptions="{ lazy: true, onLazyLoad: loadCarsLazy, itemSize: 46, delay: 200, showLoader: true, loading: lazyLoading, numToleratedItems: 10 }">
<Column field="id" header="Id" style="width: 20%">
<template #loading>
<div class="flex items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }">
<Skeleton width="60%" height="1rem" />
</div>
</template>
</Column>
<Column field="vin" header="Vin" style="width: 20%">
<template #loading>
<div class="flex items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }">
<Skeleton width="40%" height="1rem" />
</div>
</template>
</Column>
<Column field="year" header="Year" style="width: 20%">
<template #loading>
<div class="flex items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }">
<Skeleton width="30%" height="1rem" />
</div>
</template>
</Column>
<Column field="brand" header="Brand" style="width: 20%">
<template #loading>
<div class="flex items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }">
<Skeleton width="40%" height="1rem" />
</div>
</template>
</Column>
<Column field="color" header="Color" style="width: 20%">
<template #loading>
<div class="flex items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }">
<Skeleton width="60%" height="1rem" />
</div>
</template>
</Column>
</DataTable>
欄位可以群組在 Row 元件內,並且群組可以顯示在 ColumnGroup 元件內。這些群組可以使用 type 屬性來顯示,該屬性可以是 header 或 footer。要跨越的儲存格和列數是使用 Column 的 colspan 和 rowspan 屬性來定義。
<DataTable :value="sales" tableStyle="min-width: 50rem">
<ColumnGroup type="header">
<Row>
<Column header="Product" :rowspan="3" />
<Column header="Sale Rate" :colspan="4" />
</Row>
<Row>
<Column header="Sales" :colspan="2" />
<Column header="Profits" :colspan="2" />
</Row>
<Row>
<Column header="Last Year" sortable field="lastYearSale" />
<Column header="This Year" sortable field="thisYearSale" />
<Column header="Last Year" sortable field="lastYearProfit" />
<Column header="This Year" sortable field="thisYearProfit" />
</Row>
</ColumnGroup>
<Column field="product" />
<Column field="lastYearSale">
<template #body="slotProps"> {{ slotProps.data.lastYearSale }}% </template>
</Column>
<Column field="thisYearSale">
<template #body="slotProps"> {{ slotProps.data.thisYearSale }}% </template>
</Column>
<Column field="lastYearProfit">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.lastYearProfit) }}
</template>
</Column>
<Column field="thisYearProfit">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.thisYearProfit) }}
</template>
</Column>
<ColumnGroup type="footer">
<Row>
<Column footer="Totals:" :colspan="3" footerStyle="text-align:right" />
<Column :footer="lastYearTotal" />
<Column :footer="thisYearTotal" />
</Row>
</ColumnGroup>
</DataTable>
可以使用 groupRowsBy 屬性將資料列分組。當 rowGroupMode 設定為 subheader 時,每個群組可以顯示標頭和頁尾。群組標頭的內容由 groupheader 提供,頁尾的內容由 groupfooter 插槽提供。
<DataTable :value="customers" rowGroupMode="subheader" groupRowsBy="representative.name" sortMode="single"
sortField="representative.name" :sortOrder="1" scrollable scrollHeight="400px" tableStyle="min-width: 50rem">
<Column field="representative.name" header="Representative"></Column>
<Column field="name" header="Name" style="min-width: 200px"></Column>
<Column field="country" header="Country" style="min-width: 200px">
<template #body="slotProps">
<div class="flex items-center gap-2">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${slotProps.data.country.code}`" style="width: 24px" />
<span>{{ slotProps.data.country.name }}</span>
</div>
</template>
</Column>
<Column field="company" header="Company" style="min-width: 200px"></Column>
<Column field="status" header="Status" style="min-width: 200px">
<template #body="slotProps">
<Tag :value="slotProps.data.status" :severity="getSeverity(slotProps.data.status)" />
</template>
</Column>
<Column field="date" header="Date" style="min-width: 200px"></Column>
<template #groupheader="slotProps">
<div class="flex items-center gap-2">
<img :alt="slotProps.data.representative.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${slotProps.data.representative.image}`" width="32" style="vertical-align: middle" />
<span>{{ slotProps.data.representative.name }}</span>
</div>
</template>
<template #groupfooter="slotProps">
<div class="flex justify-end font-bold w-full">Total Customers: {{ calculateCustomerTotal(slotProps.data.representative.name) }}</div>
</template>
</DataTable>
當基於子標頭的資料列分組中存在 expandableRowGroups 時,群組可以展開和摺疊。展開的狀態使用 expandedRows 屬性和 rowgroup-expand 和 rowgroup-collapse 事件來控制。
<DataTable v-model:expandedRowGroups="expandedRowGroups" :value="customers" tableStyle="min-width: 50rem"
expandableRowGroups rowGroupMode="subheader" groupRowsBy="representative.name" @rowgroup-expand="onRowGroupExpand" @rowgroup-collapse="onRowGroupCollapse"
sortMode="single" sortField="representative.name" :sortOrder="1">
<template #groupheader="slotProps">
<img :alt="slotProps.data.representative.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${slotProps.data.representative.image}`" width="32" style="vertical-align: middle; display: inline-block" class="ml-2" />
<span class="align-middle ml-2 font-bold leading-normal">{{ slotProps.data.representative.name }}</span>
</template>
<Column field="representative.name" header="Representative"></Column>
<Column field="name" header="Name" style="width: 20%"></Column>
<Column field="country" header="Country" style="width: 20%">
<template #body="slotProps">
<div class="flex items-center gap-2">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${slotProps.data.country.code}`" style="width: 24px" />
<span>{{ slotProps.data.country.name }}</span>
</div>
</template>
</Column>
<Column field="company" header="Company" style="width: 20%"></Column>
<Column field="status" header="Status" style="width: 20%">
<template #body="slotProps">
<Tag :value="slotProps.data.status" :severity="getSeverity(slotProps.data.status)" />
</template>
</Column>
<Column field="date" header="Date" style="width: 20%"></Column>
<template #groupfooter="slotProps">
<div class="flex justify-end font-bold w-full">Total Customers: {{ calculateCustomerTotal(slotProps.data.representative.name) }}</div>
</template>
</DataTable>
當 rowGroupMode 設定為 rowspan 時,分組的欄位會跨越多個資料列。
<DataTable :value="customers" rowGroupMode="rowspan" groupRowsBy="representative.name" sortMode="single" sortField="representative.name" :sortOrder="1" tableStyle="min-width: 50rem">
<Column header="#" headerStyle="width:3rem">
<template #body="slotProps">
{{ slotProps.index + 1 }}
</template>
</Column>
<Column field="representative.name" header="Representative" style="min-width: 200px">
<template #body="slotProps">
<div class="flex items-center gap-2">
<img :alt="slotProps.data.representative.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${slotProps.data.representative.image}`" width="32" style="vertical-align: middle" />
<span>{{ slotProps.data.representative.name }}</span>
</div>
</template>
</Column>
<Column field="name" header="Name" style="min-width: 200px"></Column>
<Column field="country" header="Country" style="min-width: 150px">
<template #body="slotProps">
<div class="flex items-center gap-2">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${slotProps.data.country.code}`" style="width: 24px" />
<span>{{ slotProps.data.country.name }}</span>
</div>
</template>
</Column>
<Column field="company" header="Company" style="min-width: 200px"></Column>
<Column field="status" header="Status" style="min-width: 100px">
<template #body="slotProps">
<Tag :value="slotProps.data.status" :severity="getSeverity(slotProps.data.status)" />
</template>
</Column>
</DataTable>
特定的資料列和儲存格可以根據條件設定樣式。rowClass 接收資料列資料作為參數,以返回資料列的樣式類別,而儲存格則使用 body 樣板進行自訂。
<DataTable :value="products" :rowClass="rowClass" :rowStyle="rowStyle" tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity">
<template #body="slotProps">
<Badge :value="slotProps.data.quantity" :severity="stockSeverity(slotProps.data)" />
</template>
</Column>
</DataTable>
當啟用 resizableColumns 時,可以使用拖放來調整欄位大小。預設的大小調整模式為 fit,不會變更表格的整體寬度。
<DataTable :value="products" resizableColumns columnResizeMode="fit" showGridlines tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
將 columnResizeMode 設定為 expand 也會變更表格的寬度。
<DataTable :value="products" resizableColumns columnResizeMode="expand" showGridlines tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
可以使用拖放來變更欄位和資料列的順序。透過新增 reorderableColumns 屬性來設定欄位的重新排序。
同樣地,將 rowReorder 屬性新增至欄位可以啟用可拖曳的資料列。對於拖曳控制柄,欄位需要有 rowReorder 屬性,並且表格需要有 row-reorder 事件,才能在重新排序完成後控制資料列的狀態。
<DataTable :value="products" :reorderableColumns="true" @columnReorder="onColReorder" @rowReorder="onRowReorder" tableStyle="min-width: 50rem">
<Column rowReorder headerStyle="width: 3rem" :reorderableColumn="false" />
<Column v-for="col of columns" :field="col.field" :header="col.header" :key="col.field"></Column>
</DataTable>
可以透過動態欄位來實作基於條件的欄位可見性,在此範例中,使用 MultiSelect 來管理可見的欄位。
<DataTable :value="products" tableStyle="min-width: 50rem">
<template #header>
<div style="text-align:left">
<MultiSelect :modelValue="selectedColumns" :options="columns" optionLabel="header" @update:modelValue="onToggle"
display="chip" placeholder="Select Columns" />
</div>
</template>
<Column field="code" header="Code" />
<Column v-for="(col, index) of selectedColumns" :field="col.field" :header="col.header" :key="col.field + '_' + index"></Column>
</DataTable>
DataTable 可以將其資料匯出為 CSV 格式。
<DataTable :value="products" ref="dt" tableStyle="min-width: 50rem">
<template #header>
<div class="text-end pb-4">
<Button icon="pi pi-external-link" label="Export" @click="exportCSV($event)" />
</div>
</template>
<Column field="code" header="Code" exportHeader="Product Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
DataTable 透過 contextMenu 事件與關聯選單有獨特的整合,可在右鍵單擊時開啟選單,同時使用 contextMenuSelection 屬性和 row-contextmenu 事件來控制透過選單的選擇。
<ContextMenu ref="cm" :model="menuModel" @hide="selectedProduct = null" />
<DataTable v-model:contextMenuSelection="selectedProduct" :value="products" contextMenu
@row-contextmenu="onRowContextMenu" tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="price" header="Price">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.price) }}
</template>
</Column>
</DataTable>
狀態保持表格允許將狀態(例如頁面、排序和篩選)儲存在本機儲存空間或工作階段儲存空間中,以便在再次造訪頁面時,表格將使用上次的設定來呈現資料。
變更表格的狀態,例如分頁、離開並再次返回此表格以測試此功能,設定會使用 stateStorage 屬性設定為 session,以便表格在瀏覽器關閉之前保持狀態。另一個替代方法是 local,是指向 localStorage 以延長生命週期。
<DataTable v-model:filters="filters" v-model:selection="selectedCustomer" :value="customers"
stateStorage="session" stateKey="dt-state-demo-session" paginator :rows="5" filterDisplay="menu"
selectionMode="single" dataKey="id" :globalFilterFields="['name', 'country.name', 'representative.name', 'status']" tableStyle="min-width: 50rem">
<template #header>
<IconField>
<InputIcon>
<i class="pi pi-search" />
</InputIcon>
<InputText v-model="filters['global'].value" placeholder="Global Search" />
</IconField>
</template>
<Column field="name" header="Name" sortable style="width: 25%">
<template #filter="{ filterModel }">
<InputText v-model="filterModel.value" type="text" placeholder="Search by name" />
</template>
</Column>
<Column header="Country" sortable sortField="country.name" filterField="country.name" filterMatchMode="contains" style="width: 25%">
<template #body="{ data }">
<div class="flex items-center gap-2">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${data.country.code}`" style="width: 24px" />
<span>{{ data.country.name }}</span>
</div>
</template>
<template #filter="{ filterModel }">
<InputText v-model="filterModel.value" type="text" placeholder="Search by country" />
</template>
</Column>
<Column header="Representative" sortable sortField="representative.name" filterField="representative" :showFilterMatchModes="false" :filterMenuStyle="{ width: '14rem' }" style="width: 25%">
<template #body="{ data }">
<div class="flex items-center gap-2">
<img :alt="data.representative.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${data.representative.image}`" style="width: 32px" />
<span>{{ data.representative.name }}</span>
</div>
</template>
<template #filter="{ filterModel }">
<MultiSelect v-model="filterModel.value" :options="representatives" optionLabel="name" placeholder="Any">
<template #option="slotProps">
<div class="flex items-center gap-2">
<img :alt="slotProps.option.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${slotProps.option.image}`" style="width: 32px" />
<span>{{ slotProps.option.name }}</span>
</div>
</template>
</MultiSelect>
</template>
</Column>
<Column field="status" header="Status" sortable filterMatchMode="equals" style="width: 25%">
<template #body="{ data }">
<Tag :value="data.status" :severity="getSeverity(data.status)" />
</template>
<template #filter="{ filterModel }">
<Select v-model="filterModel.value" :options="statuses" placeholder="Select One" showClear>
<template #option="slotProps">
<Tag :value="slotProps.option" :severity="getSeverity(slotProps.option)" />
</template>
</Select>
</template>
</Column>
<template #empty> No customers found. </template>
</DataTable>
具有選取、分頁、篩選、排序和樣板的 DataTable。
<DataTable v-model:filters="filters" v-model:selection="selectedCustomers" :value="customers" paginator :rows="10" dataKey="id" filterDisplay="menu"
:globalFilterFields="['name', 'country.name', 'representative.name', 'balance', 'status']">
<template #header>
<div class="flex justify-between">
<Button type="button" icon="pi pi-filter-slash" label="Clear" outlined @click="clearFilter()" />
<IconField>
<InputIcon>
<i class="pi pi-search" />
</InputIcon>
<InputText v-model="filters['global'].value" placeholder="Keyword Search" />
</IconField>
</div>
</template>
<template #empty> No customers found. </template>
<Column selectionMode="multiple" headerStyle="width: 3rem"></Column>
<Column field="name" header="Name" sortable style="min-width: 14rem">
<template #body="{ data }">
{{ data.name }}
</template>
<template #filter="{ filterModel }">
<InputText v-model="filterModel.value" type="text" placeholder="Search by name" />
</template>
</Column>
<Column header="Country" sortable sortField="country.name" filterField="country.name" style="min-width: 14rem">
<template #body="{ data }">
<div class="flex items-center gap-2">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${data.country.code}`" style="width: 24px" />
<span>{{ data.country.name }}</span>
</div>
</template>
<template #filter="{ filterModel }">
<InputText v-model="filterModel.value" type="text" placeholder="Search by country" />
</template>
</Column>
<Column header="Agent" sortable sortField="representative.name" filterField="representative" :showFilterMatchModes="false" :filterMenuStyle="{ width: '14rem' }" style="min-width: 14rem">
<template #body="{ data }">
<div class="flex items-center gap-2">
<img :alt="data.representative.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${data.representative.image}`" style="width: 32px" />
<span>{{ data.representative.name }}</span>
</div>
</template>
<template #filter="{ filterModel }">
<MultiSelect v-model="filterModel.value" :options="representatives" optionLabel="name" placeholder="Any">
<template #option="slotProps">
<div class="flex items-center gap-2">
<img :alt="slotProps.option.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${slotProps.option.image}`" style="width: 32px" />
<span>{{ slotProps.option.name }}</span>
</div>
</template>
</MultiSelect>
</template>
</Column>
<Column field="date" header="Date" sortable filterField="date" dataType="date" style="min-width: 10rem">
<template #body="{ data }">
{{ formatDate(data.date) }}
</template>
<template #filter="{ filterModel }">
<DatePicker v-model="filterModel.value" dateFormat="mm/dd/yy" placeholder="mm/dd/yyyy" />
</template>
</Column>
<Column field="balance" header="Balance" sortable filterField="balance" dataType="numeric" style="min-width: 10rem">
<template #body="{ data }">
{{ formatCurrency(data.balance) }}
</template>
<template #filter="{ filterModel }">
<InputNumber v-model="filterModel.value" mode="currency" currency="USD" locale="en-US" />
</template>
</Column>
<Column header="Status" field="status" sortable :filterMenuStyle="{ width: '14rem' }" style="min-width: 12rem">
<template #body="{ data }">
<Tag :value="data.status" :severity="getSeverity(data.status)" />
</template>
<template #filter="{ filterModel }">
<Select v-model="filterModel.value" :options="statuses" placeholder="Select One" showClear>
<template #option="slotProps">
<Tag :value="slotProps.option" :severity="getSeverity(slotProps.option)" />
</template>
</Select>
</template>
</Column>
<Column field="activity" header="Activity" sortable :showFilterMatchModes="false" style="min-width: 12rem">
<template #body="{ data }">
<ProgressBar :value="data.activity" :showValue="false" style="height: 6px"></ProgressBar>
</template>
<template #filter="{ filterModel }">
<Slider v-model="filterModel.value" range class="m-4"></Slider>
<div class="flex items-center justify-between px-2">
<span>{{ filterModel.value ? filterModel.value[0] : 0 }}</span>
<span>{{ filterModel.value ? filterModel.value[1] : 100 }}</span>
</div>
</template>
</Column>
<Column headerStyle="width: 5rem; text-align: center" bodyStyle="text-align: center; overflow: visible">
<template #body>
<Button type="button" icon="pi pi-cog" rounded />
</template>
</Column>
</DataTable>
具有對話框的 CRUD 實作範例。
<Toolbar class="mb-6">
<template #start>
<Button label="New" icon="pi pi-plus" class="mr-2" @click="openNew" />
<Button label="Delete" icon="pi pi-trash" severity="danger" outlined @click="confirmDeleteSelected" :disabled="!selectedProducts || !selectedProducts.length" />
</template>
<template #end>
<FileUpload mode="basic" accept="image/*" :maxFileSize="1000000" label="Import" customUpload chooseLabel="Import" class="mr-2" auto :chooseButtonProps="{ severity: 'secondary' }" />
<Button label="Export" icon="pi pi-upload" severity="secondary" @click="exportCSV($event)" />
</template>
</Toolbar>
<DataTable
ref="dt"
v-model:selection="selectedProducts"
:value="products"
dataKey="id"
:paginator="true"
:rows="10"
:filters="filters"
paginatorTemplate="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink CurrentPageReport RowsPerPageDropdown"
:rowsPerPageOptions="[5, 10, 25]"
currentPageReportTemplate="Showing {first} to {last} of {totalRecords} products"
>
<template #header>
<div class="flex flex-wrap gap-2 items-center justify-between">
<h4 class="m-0">Manage Products</h4>
<IconField>
<InputIcon>
<i class="pi pi-search" />
</InputIcon>
<InputText v-model="filters['global'].value" placeholder="Search..." />
</IconField>
</div>
</template>
<Column selectionMode="multiple" style="width: 3rem" :exportable="false"></Column>
<Column field="code" header="Code" sortable style="min-width: 12rem"></Column>
<Column field="name" header="Name" sortable style="min-width: 16rem"></Column>
<Column header="Image">
<template #body="slotProps">
<img :src="`https://primefaces.org/cdn/primevue/images/product/${slotProps.data.image}`" :alt="slotProps.data.image" class="rounded" style="width: 64px" />
</template>
</Column>
<Column field="price" header="Price" sortable style="min-width: 8rem">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.price) }}
</template>
</Column>
<Column field="category" header="Category" sortable style="min-width: 10rem"></Column>
<Column field="rating" header="Reviews" sortable style="min-width: 12rem">
<template #body="slotProps">
<Rating :modelValue="slotProps.data.rating" :readonly="true" />
</template>
</Column>
<Column field="inventoryStatus" header="Status" sortable style="min-width: 12rem">
<template #body="slotProps">
<Tag :value="slotProps.data.inventoryStatus" :severity="getStatusLabel(slotProps.data.inventoryStatus)" />
</template>
</Column>
<Column :exportable="false" style="min-width: 12rem">
<template #body="slotProps">
<Button icon="pi pi-pencil" outlined rounded class="mr-2" @click="editProduct(slotProps.data)" />
<Button icon="pi pi-trash" outlined rounded severity="danger" @click="confirmDeleteProduct(slotProps.data)" />
</template>
</Column>
</DataTable>
DataTable 使用 table 元素,其屬性可以使用 tableProps 選項來擴充。此屬性允許傳遞 aria 角色和屬性,例如 aria-label 和 aria-describedby,以定義閱讀器的表格。表格的預設角色為 table。標頭、主體和頁尾元素使用 rowgroup,資料列使用 row 角色,標頭儲存格具有 columnheader,主體儲存格使用 cell 角色。可排序的標頭使用 aria-sort 屬性,設定為「遞增」或「遞減」。
用於資料列選取的內建核取方塊和單選按鈕元件使用 checkbox 和 radiobutton。描述它們的標籤是從 locale API 的 aria.selectRow 和 aria.unselectRow 屬性中擷取的。同樣地,標頭核取方塊使用 selectAll 和 unselectAll 金鑰。當選取資料列時,會將 aria-selected 設定為 true。
用於展開或摺疊資料列的元素是一個具有 aria-expanded 和 aria-controls 屬性的 button。描述按鈕的值是從 locale API 的 aria.expandRow 和 aria.collapseRow 屬性中取得的。
篩選選單按鈕除了 aria-haspopup、aria-expanded 和 aria-controls 之外,還使用 aria.showFilterMenu 和 aria.hideFilterMenu 屬性作為 aria-label,以定義按鈕和覆蓋之間的關係。彈出選單具有 dialog 角色,並將 aria-modal 設為在覆蓋中保持焦點。運算子下拉式選單使用 aria.filterOperator,而篩選條件下拉式選單則使用 aria.filterConstraint 屬性。另一方面,用於新增規則的按鈕則使用 aria.addRule 和 aria.removeRule 屬性。頁尾按鈕類似地使用 aria.clear 和 aria.apply 屬性。如果使用樣板來使用自訂元件,則可以使用 Column 元件的 filterInputProps 為內建篩選元件定義 aria 標籤,您也可以定義自己的 aria 標籤。
可編輯的儲存格使用自訂樣板,因此如果需要,您需要手動管理 aria 角色和屬性。資料列編輯器控制項是按鈕元素,其 aria-label 使用 aria.editRow、aria.cancelEdit 和 aria.saveEdit。
分頁器是 DataTable 中使用的獨立元件,請參閱 分頁器 以取得有關輔助功能功能的詳細資訊。
DataTable 中用於篩選、資料列展開、編輯等情況的任何按鈕元素都可以使用 Tab 鍵瀏覽,並且可以使用 space 和 enter 鍵。
按鍵 | 功能 |
---|---|
tab | 在標頭之間移動。 |
enter | 排序欄位。 |
space | 排序欄位。 |
按鍵 | 功能 |
---|---|
tab | 在彈出視窗內的元素之間移動。 |
escape | 隱藏彈出視窗。 |
按鍵 | 功能 |
---|---|
tab | 將焦點移至第一個選取的資料列,如果沒有選取的資料列,則將焦點移至第一個資料列。 |
上箭頭 | 將焦點移至前一個資料列。 |
下箭頭 | 將焦點移至下一個資料列。 |
enter | 根據 metaKeySelection 設定,切換焦點資料列的選取狀態。 |
space | 根據 metaKeySelection 設定,切換焦點資料列的選取狀態。 |
home | 將焦點移至第一個資料列。 |
end | 將焦點移至最後一個資料列。 |
shift + 下箭頭 | 將焦點移至下一個資料列,並切換選取狀態。 |
shift + 上箭頭 | 將焦點移至前一個資料列,並切換選取狀態。 |
shift + space | 選取最近選取的資料列和焦點資料列之間的資料列。 |
control + shift + home | 選取焦點資料列和所有直到第一個選項的選項。 |
control + shift + end | 選取焦點資料列和所有直到最後一個選項的選項。 |
control + a | 選取所有資料列。 |