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,请参阅分页器组件,了解有关高级自定义选项的更多信息。
<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>
在列上将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>
在列上将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,使用列的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来保存正在编辑的行的引用,来配置行编辑。与单元格编辑模式类似,使用列的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属性在水平滚动期间固定列。位置使用alignFrozen定义,可以是left或right。
<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。要跨越的单元格数和行数使用列的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 事件与 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-label 和 aria-describedby 之类的 aria 角色和属性,以便为阅读器定义表格。表格的默认角色是 table。头部、主体和页脚元素使用 rowgroup,行使用 row 角色,头部单元格具有 columnheader,而主体单元格使用 cell 角色。可排序的标题使用 aria-sort 属性,将其设置为“ascending”或“descending”。
用于行选择的内置复选框和单选按钮组件使用 checkbox 和 radiobutton。描述它们的标签从 locale API 的 aria.selectRow 和 aria.unselectRow 属性中检索。类似地,标题复选框使用 selectAll 和 unselectAll 键。选择某一行时,该行的 aria-selected 设置为 true。
用于展开或折叠行的元素是 button,带有 aria-expanded 和 aria-controls 属性。用于描述按钮的值从 locale API 的 aria.expandRow 和 aria.collapseRow 属性派生。
过滤菜单按钮使用 aria.showFilterMenu 和 aria.hideFilterMenu 属性作为 aria-label,此外还有 aria-haspopup、aria-expanded 和 aria-controls,以定义按钮和覆盖层之间的关系。弹出菜单具有 dialog 角色,aria-modal 在覆盖层内保持焦点。运算符下拉列表使用 aria.filterOperator,而过滤约束下拉列表使用 aria.filterConstraint 属性。另一方面,添加规则的按钮使用 aria.addRule 和 aria.removeRule 属性。页脚按钮类似地使用 aria.clear 和 aria.apply 属性。Column 组件的 filterInputProps 可用于为内置过滤组件定义 aria 标签。如果使用了带模板的自定义组件,您也可以定义自己的 aria 标签。
可编辑单元格使用自定义模板,因此如果需要,您需要手动管理 aria 角色和属性。行编辑器控件是按钮元素,aria.editRow、aria.cancelEdit 和 aria.saveEdit 用于 aria-label。
分页器是在 DataTable 内部使用的独立组件,有关辅助功能功能的更多信息,请参阅 分页器。
DataTable 中用于过滤、行展开和编辑等情况的任何按钮元素都是可跳跃的,并且可以使用 空格 和 回车 键。
按键 | 功能 |
---|---|
tab | 在标题之间移动。 |
回车 | 对列进行排序。 |
空格 | 对列进行排序。 |
按键 | 功能 |
---|---|
tab | 在弹出窗口内的元素之间移动。 |
Esc | 隐藏弹出窗口。 |
按键 | 功能 |
---|---|
tab | 将焦点移动到第一个选定的行,如果没有,则第一个行接收焦点。 |
向上箭头 | 将焦点移动到上一行。 |
向下箭头 | 将焦点移动到下一行。 |
回车 | 根据 metaKeySelection 设置切换焦点行的选定状态。 |
空格 | 根据 metaKeySelection 设置切换焦点行的选定状态。 |
Home | 将焦点移动到第一行。 |
End | 将焦点移动到最后一行。 |
shift + 向下箭头 | 将焦点移动到下一行并切换选择状态。 |
shift + 向上箭头 | 将焦点移动到上一行并切换选择状态。 |
shift + 空格 | 选择最近选择的行和焦点行之间的行。 |
control + shift + Home | 选择焦点行以及所有直到第一个选项的选项。 |
control + shift + End | 选择焦点行以及所有直到最后一个选项的选项。 |
control + a | 选择所有行。 |