树形表格

树形表格用于以表格格式显示分层数据。


import TreeTable from 'primevue/treetable';
import Column from 'primevue/column';

树形表格需要 TreeNode 实例的集合作为 value,以及 Column 组件作为子项进行表示。带有切换节点元素的列应启用 expander


<TreeTable :value="nodes" tableStyle="min-width: 50rem">
    <Column field="name" header="Name" expander style="width: 34%"></Column>
    <Column field="size" header="Size" style="width: 33%"></Column>
    <Column field="type" header="Type" style="width: 33%"></Column>
</TreeTable>

可以以编程方式创建列。


<TreeTable :value="nodes" tableStyle="min-width: 50rem">
    <Column v-for="col of columns" :key="col.field" :field="col.field" :header="col.header" :expander="col.expander"></Column>
</TreeTable>

使用 expandedKeys 属性控制展开状态。expandedKeys 应该是一个对象,其键引用节点键,值表示展开状态,例如 {'0-0': true}


<Button @click="toggleApplications" label="Toggle Applications" />
<TreeTable v-model:expandedKeys="expandedKeys" :value="nodes" class="mt-6" tableStyle="min-width: 50rem">
    <Column field="name" header="Name" expander style="width: 34%"></Column>
    <Column field="size" header="Size" style="width: 33%"></Column>
    <Column field="type" header="Type" style="width: 33%"></Column>
</TreeTable>

通过模板支持 headerfooter 插槽处的自定义内容。


<TreeTable :value="nodes" tableStyle="min-width: 50rem">
    <template #header>
        <div class="text-xl font-bold">File Viewer</div>
    </template>
    <Column field="name" header="Name" expander style="width: 250px"></Column>
    <Column field="size" header="Size" style="width: 150px"></Column>
    <Column field="type" header="Type" style="width: 150px"></Column>
    <Column style="width: 10rem">
        <template #body>
            <div class="flex flex-wrap gap-2">
                <Button type="button" icon="pi pi-search" rounded />
                <Button type="button" icon="pi pi-pencil" rounded severity="success" />
            </div>
        </template>
    </Column>
    <template #footer>
        <div class="flex justify-start">
            <Button icon="pi pi-refresh" label="Reload" severity="warn" />
        </div>
    </template>
</TreeTable>

除了常规表格外,还提供具有替代大小的替代方案。


<TreeTable :value="nodes" :size="size.value" tableStyle="min-width: 50rem">
    <Column field="name" header="Name" expander style="width: 34%"></Column>
    <Column field="size" header="Size" style="width: 33%"></Column>
    <Column field="type" header="Type" style="width: 33%"></Column>
</TreeTable>

通过添加 paginator 属性并定义每页 rows 来启用分页。


<TreeTable :value="nodes" :paginator="true" :rows="5" :rowsPerPageOptions="[5, 10, 25]" tableStyle="min-width: 50rem">
    <Column field="name" header="Name" expander style="width: 34%"></Column>
    <Column field="size" header="Size" style="width: 33%"></Column>
    <Column field="type" header="Type" style="width: 33%"></Column>
</TreeTable>

使用 paginatorTemplate 属性自定义分页器 UI。每个元素还可以使用您自己的 UI 进行进一步自定义以替换默认的 UI,有关高级自定义选项的更多信息,请参阅 分页器 组件。


<TreeTable
    :value="nodes"
    :paginator="true"
    :rows="5"
    :rowsPerPageOptions="[5, 10, 25, 50]"
    paginatorTemplate="RowsPerPageDropdown FirstPageLink PrevPageLink CurrentPageReport NextPageLink LastPageLink"
    currentPageReportTemplate="{first} to {last} of {totalRecords}"
    tableStyle="min-width: 50rem"
>
    <template #paginatorstart>
        <Button type="button" icon="pi pi-refresh" text />
    </template>
    <Column field="name" header="Name" expander style="width: 34%"></Column>
    <Column field="size" header="Size" style="width: 33%"></Column>
    <Column field="type" header="Type" style="width: 33%"></Column>
    <template #paginatorend>
        <Button type="button" icon="pi pi-download" text />
    </template>
</TreeTable>

通过添加 paginator 属性并定义每页 rows 来启用分页。


<TreeTable :value="nodes" :paginator="true" :rows="5" :rowsPerPageOptions="[5, 10, 25]" tableStyle="min-width: 50rem">
    <Column field="name" header="Name" expander style="width: 34%"></Column>
    <Column field="size" header="Size" style="width: 33%"></Column>
    <Column field="type" header="Type" style="width: 33%"></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>
</TreeTable>

通过添加 sortable 属性启用列的排序。


<TreeTable :value="nodes" tableStyle="min-width: 50rem">
    <Column field="name" header="Name" sortable expander style="width: 34%"></Column>
    <Column field="size" header="Size" sortable style="width: 33%"></Column>
    <Column field="type" header="Type" sortable style="width: 33%"></Column>
</TreeTable>

可以通过将 sortMode 定义为 multiple 来对多列进行排序。此模式需要在单击标题时按下元键(例如 )。


<TreeTable :value="nodes" sortMode="multiple" tableStyle="min-width: 50rem">
    <Column field="name" header="Name" sortable expander style="width: 34%"></Column>
    <Column field="size" header="Size" sortable style="width: 33%"></Column>
    <Column field="type" header="Type" sortable style="width: 33%"></Column>
</TreeTable>

当存在 removableSort 时,第三次单击会从列中删除排序。


<TreeTable :value="nodes" sortMode="multiple" removableSort tableStyle="min-width: 50rem">
    <Column field="name" header="Name" sortable expander style="width: 34%"></Column>
    <Column field="size" header="Size" sortable style="width: 33%"></Column>
    <Column field="type" header="Type" sortable style="width: 33%"></Column>
</TreeTable>

通过向列添加 filter 属性来启用筛选。filterMode 指定筛选策略,在 lenient 模式下,当查询匹配一个节点时,不会进一步搜索该节点的子节点,因为该节点的所有后代都包含在内。另一方面,在 strict 模式下,当查询匹配一个节点时,筛选会继续对所有后代进行。


<SelectButton v-model="filterMode" optionLabel="label" dataKey="label" :options="filterOptions" />
<TreeTable :value="nodes" :filters="filters" :filterMode="filterMode.value">
    <template #header>
        <div class="flex justify-end">
            <IconField>
                <InputIcon class="pi pi-search" />
                <InputText v-model="filters['global']" placeholder="Global Search" />
            </IconField>
        </div>
    </template>
    <Column field="name" header="Name" expander style="min-width: 12rem">
        <template #filter>
            <InputText v-model="filters['name']" type="text" placeholder="Filter by name" />
        </template>
    </Column>
    <Column field="size" header="Size" style="min-width: 12rem">
        <template #filter>
            <InputText v-model="filters['size']" type="text" placeholder="Filter by size" />
        </template>
    </Column>
    <Column field="type" header="Type" style="min-width: 12rem">
        <template #filter>
            <InputText v-model="filters['type']" type="text" placeholder="Filter by type" />
        </template>
    </Column>
</TreeTable>

通过将 selectionMode 设置为 single 以及 selectionKeys 属性来管理选择值绑定,从而配置单节点选择。

默认情况下,需要按元键(例如 )来取消选择一个节点,但是可以通过禁用 metaKeySelection 属性来配置此选项。在支持触摸的设备中,此选项不起作用,其行为与将其设置为 false 相同。


<ToggleSwitch v-model="metaKey" inputId="input-metakey" />

<TreeTable v-model:selectionKeys="selectedKey" :value="nodes" selectionMode="single" :metaKeySelection="metaKey" tableStyle="min-width: 50rem">
    <Column field="name" header="Name" expander style="width: 34%"></Column>
    <Column field="size" header="Size" style="width: 33%"></Column>
    <Column field="type" header="Type" style="width: 33%"></Column>
</TreeTable>

通过将 selectionMode 设置为 multiple,可以选择多个节点。默认情况下,在多选模式下,不需要按元键(例如 )添加到现有选择中。当存在可选的 metaKeySelection 时,其行为会发生更改,即选择新节点需要存在元键。请注意,在支持触摸的设备中,树形表格始终忽略元键。

在多选模式下,值绑定应为键值对,其中键是节点键,值是一个布尔值,用于指示选择。


<ToggleSwitch v-model="metaKey" inputId="input-metakey" />

<TreeTable v-model:selectionKeys="selectedKey" :value="nodes" selectionMode="multiple" :metaKeySelection="metaKey" tableStyle="min-width: 50rem">
    <Column field="name" header="Name" expander style="width: 34%"></Column>
    <Column field="size" header="Size" style="width: 33%"></Column>
    <Column field="type" header="Type" style="width: 33%"></Column>
</TreeTable>

通过将 selectionMode 配置为 checkbox,可以通过复选框选择多个节点。

在复选框选择模式下,值绑定应为键值对,其中键(或 dataKey)是节点键,值是一个对象,该对象具有 checkedpartialChecked 属性来表示节点的选中状态。


{
    '0-0': {
        partialChecked: false,
        checked: true
    }
}


<TreeTable v-model:selectionKeys="selectedKey" :value="nodes" selectionMode="checkbox" tableStyle="min-width: 50rem">
    <Column field="name" header="Name" expander style="width: 34%"></Column>
    <Column field="size" header="Size" style="width: 33%"></Column>
    <Column field="type" header="Type" style="width: 33%"></Column>
</TreeTable>

树形表格提供 nodeSelectnodeUnselect 事件来监听选择事件。


<TreeTable v-model:selectionKeys="selectedKey" :value="nodes" selectionMode="single" @nodeSelect="onNodeSelect" @nodeUnselect="onNodeUnselect" :metaKeySelection="false" tableStyle="min-width: 50rem">
    <Column field="name" header="Name" expander style="width: 34%"></Column>
    <Column field="size" header="Size" style="width: 33%"></Column>
    <Column field="type" header="Type" style="width: 33%"></Column>
</TreeTable>

延迟模式可方便地处理大型数据集,而不是加载整个数据,每次发生 pagingsortingfiltering 时,都会通过调用相应的回调来加载小块数据。下面的示例使用内存列表和超时来模拟网络连接,从而模拟从远程数据源延迟加载数据。

启用 lazy 属性并通过执行投影查询将逻辑行数分配给 totalRecords 是实现的关键要素,以便分页器显示 UI,假设实际上存在 totalRecords 大小的记录,但实际上它们并不存在于页面上,只存在当前页面上显示的记录。

此外,应该只加载根元素,可以使用 nodeExpand 回调按需加载子元素。


<TreeTable :value="nodes" :lazy="true" :paginator="true" :rows="rows" :loading="loading"
    @nodeExpand="onExpand" @page="onPage" :totalRecords="totalRecords" tableStyle="min-width: 50rem">
    <Column field="name" header="Name" expander></Column>
    <Column field="size" header="Size"></Column>
    <Column field="type" header="Type"></Column>
</TreeTable>

添加 scrollable 属性以及数据视口的 scrollHeight,可以启用带有固定标题的垂直滚动。


<TreeTable :value="nodes" scrollable scrollHeight="270px" tableStyle="min-width: 50rem">
    <Column field="name" header="Name" expander style="width: 34%"></Column>
    <Column field="size" header="Size" style="width: 33%"></Column>
    <Column field="type" header="Type" style="width: 33%"></Column>
</TreeTable>

灵活滚动功能使可滚动视口部分动态化,而不是固定值,以便它可以相对于表格的父大小增长或收缩。单击下面的按钮以显示一个可最大化的对话框,其中数据视口会根据大小变化自行调整。


<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' }">
    <TreeTable :value="nodes" :scrollable="true" scrollHeight="flex" tableStyle="min-width: 50rem">
        <Column field="name" header="Name" :expander="true" style="min-width: 200px"></Column>
        <Column field="size" header="Size" style="min-width: 200px"></Column>
        <Column field="type" header="Type" style="min-width: 200px"></Column>
    </TreeTable>
    <template #footer>
        <Button label="Ok" icon="pi pi-check" @click="dialogVisible = false" />
    </template>
</Dialog>

当表格宽度超过父宽度时,会显示水平滚动条。


<TreeTable :value="nodes" scrollable scrollHeight="300px">
    <Column field="name" header="Name" expander style="min-width: 250px"></Column>
    <Column field="size" header="Size" style="min-width: 200px"></Column>
    <Column field="type" header="Type 2" style="min-width: 200px"></Column>
    <Column field="size" header="Size 2" style="min-width: 200px"></Column>
    <Column field="type" header="Type 3" style="min-width: 200px"></Column>
    <Column field="size" header="Size 3" style="min-width: 200px"></Column>
</TreeTable>

可以通过在列上启用 frozen 属性,在水平滚动期间固定列。该位置是通过可以是 leftrightalignFrozen 定义的。


<TreeTable :value="nodes" scrollable scrollHeight="300px">
    <Column field="name" header="Name" expander frozen style="min-width: 250px" class="font-bold"></Column>
    <Column field="size" header="Size" style="min-width: 200px"></Column>
    <Column field="type" header="Type 2" style="min-width: 200px"></Column>
    <Column field="size" header="Size 2" style="min-width: 200px"></Column>
    <Column field="type" header="Type 3" style="min-width: 200px"></Column>
    <Column field="size" header="Size 3" style="min-width: 200px"></Column>
</TreeTable>

启用 resizableColumns 后,可以通过拖放来调整列大小。默认调整大小模式是 fit,该模式不会更改表格的整体宽度。


<TreeTable :value="nodes" :resizableColumns="true" showGridlines tableStyle="min-width: 50rem">
    <Column field="name" header="Name" expander></Column>
    <Column field="size" header="Size"></Column>
    <Column field="type" header="Type"></Column>
</TreeTable>

columnResizeMode 设置为 expand 也会更改表格宽度。


<TreeTable :value="nodes" :resizableColumns="true" columnResizeMode="expand" showGridlines tableStyle="min-width: 50rem">
    <Column field="name" header="Name" expander></Column>
    <Column field="size" header="Size"></Column>
    <Column field="type" header="Type"></Column>
</TreeTable>

可以使用动态列来实现基于条件的列可见性,在此示例中,使用多选来管理可见的列。


<TreeTable :value="nodes" tableStyle="min-width: 50rem">
    <template #header>
        <div style="text-align:left">
            <MultiSelect :modelValue="selectedColumns" @update:modelValue="onToggle" :options="columns" optionLabel="header" class="w-full sm:w-64" display="chip"/>
        </div>
    </template>
    <Column field="name" header="Name" :expander="true"></Column>
    <Column v-for="col of selectedColumns" :field="col.field" :header="col.header" :key="col.field"></Column>
</TreeTable>

树形表格使用 contextMenu 事件与上下文菜单进行独占集成,以在右键单击时打开菜单,以及使用 contextMenuSelection 属性和 row-contextmenu 事件来控制通过菜单进行选择。


<ContextMenu ref="cm" :model="menuModel" @hide="selectedNode = null" />
<TreeTable v-model:contextMenuSelection="selectedNode" :value="nodes" contextMenu @row-contextmenu="onRowContextMenu" tableStyle="min-width: 50rem">
    <Column field="name" header="Name" expander style="width: 34%"></Column>
    <Column field="size" header="Size" style="width: 33%"></Column>
    <Column field="type" header="Type" style="width: 33%"></Column>
</TreeTable>

屏幕阅读器

数据表格使用 treegrid 元素,可以使用 tableProps 选项扩展其属性。此属性允许将 aria 角色和属性(如 aria-labelaria-describedby)传递给阅读器定义表格。表格的默认角色是 table。标题、正文和页脚元素使用 rowgroup,行使用 row 角色,标题单元格使用 columnheader,正文单元格使用 cell 角色。可排序的标题利用 aria-sort 属性设置为 “ascending” 或 “descending”。

行元素管理状态的 aria-expanded,以及定义层次结构的 aria-posinsetaria-setsizearia-level 属性。

启用选择后,行上的 aria-selected 设置为 true。在复选框模式下,树形表格组件使用隐藏的本机复选框元素。

可编辑的单元格使用自定义模板,因此如果需要,您需要手动管理 aria 角色和属性。

分页器是数据表格内部使用的独立组件,有关可访问性功能的更多信息,请参阅 分页器

可排序标题键盘支持

功能
tab在标题之间移动。
enter对列进行排序。
space对列进行排序。

键盘支持

功能
tab当焦点进入组件时,将焦点移动到第一个选定的节点;如果没有,则第一个元素接收焦点。如果焦点已经在组件内部,则将焦点移动到页面选项卡序列中的下一个可聚焦元素。
shift + tab当焦点进入组件时,如果存在上次选中的节点,则将焦点移动到该节点。如果没有,则第一个元素获得焦点。如果焦点已在组件内,则将焦点移动到页面制表符序列中的上一个可聚焦元素。
enter选择具有焦点的树节点。
space选择具有焦点的树节点。
向下箭头将焦点移动到下一个树节点。
向上箭头将焦点移动到上一个树节点。
向右箭头如果节点已关闭,则打开节点;否则将焦点移动到第一个子节点。
向左箭头如果节点已打开,则关闭节点;否则将焦点移动到父节点。
Home键将焦点移动到第一个同级节点。
End键将焦点移动到最后一个同级节点。