> ## Content Index
> Fetch the complete content index at: https://blog.vercanti.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# PrimeVue 完全指南
- URL: https://blog.vercanti.com/primevue-wan-quan-zhi-nan/
- Published: 2026-08-28T14:35:26.000Z
- Updated: 2026-08-28T14:58:48.000Z
- Description: PrimeVue 是 PrimeTek 出品的 Vue 3 UI 组件库，提供 90+ 开箱即用的组件。v4 在 v3 基础上进行了重大架构调整：以 CSS 变量和设计令牌体系替代了 SASS 主题，并引入了 PassThrough（PT）API 实现完全无样式模式。 PrimeVue v4 提供三种开箱即用的主题预设： CSS 变量命名规则：--p-{组件}-{属性}，如 --p-button-background。 在 main.ts 中引用： PassThrough API 允许将自定义属性、类名、样式注入到组件内部任意 DOM 节点，无需覆盖 C
- Author: yellowdog
- Tags: 前端开发, Vue生态

> 官方文档：<https://primevue.org/>  
> 适用版本：PrimeVue 4.x（2026-05-07 核实）

PrimeVue 是 PrimeTek 出品的 Vue 3 UI 组件库，提供 90+ 开箱即用的组件。v4 在 v3 基础上进行了重大架构调整：以 CSS 变量和设计令牌体系替代了 SASS 主题，并引入了 PassThrough（PT）API 实现完全无样式模式。

---

## 安装与配置

### Vite 项目安装

```bash
npm install primevue @primevue/themes
# 图标库（可选，但常用）
npm install primeicons

```

### main.ts 配置

```typescript
import { createApp } from 'vue'
import PrimeVue from 'primevue/config'
import Aura from '@primevue/themes/aura'
import ToastService from 'primevue/toastservice'
import ConfirmationService from 'primevue/confirmationservice'
import App from './App.vue'

const app = createApp(App)

app.use(PrimeVue, {
  theme: {
    preset: Aura,
    options: {
      prefix: 'p',              // CSS 变量前缀，默认 'p'
      darkModeSelector: 'system', // 'system' | '.dark' | 'media' | false
      cssLayer: false           // 是否注入 @layer 以降低样式优先级（与 Tailwind 配合时设 true）
    }
  },
  ripple: true,                 // 全局启用水波纹效果
  inputVariant: 'outlined',    // 'outlined' | 'filled'，全局输入框变体
  locale: {                     // 可选：本地化配置
    accept: '确认',
    reject: '取消',
    // ... 其余语言包字段
  }
})

app.use(ToastService)
app.use(ConfirmationService)

app.mount('#app')

```

### 配置参数总表

| 参数                             | 类型              | 默认值        | 说明                                                   |
| ------------------------------ | --------------- | ---------- | ---------------------------------------------------- |
| theme.preset                   | Object          | —          | 主题预设对象（Aura/Lara/Nora 或自定义）                          |
| theme.options.prefix           | string          | 'p'        | CSS 变量前缀，改为其他值可避免命名冲突                                |
| theme.options.darkModeSelector | string \| false | 'system'   | 暗色模式触发方式：'system'（媒体查询）、自定义 CSS 类（.dark）、false（禁用暗色） |
| theme.options.cssLayer         | boolean         | false      | 将 PrimeVue 样式包裹在 CSS @layer 中，便于 Tailwind 覆盖         |
| ripple                         | boolean         | false      | 全局启用点击水波纹效果                                          |
| inputVariant                   | string          | 'outlined' | 所有输入组件的默认变体                                          |
| unstyled                       | boolean         | false      | 完全去除内置样式，配合 PassThrough API 使用                       |
| pt                             | Object          | —          | 全局 PassThrough 配置，对所有组件生效                            |
| ptOptions                      | Object          | —          | PT 合并策略选项                                            |
| locale                         | Object          | —          | 国际化文本配置                                              |
| nonce                          | string          | —          | Content Security Policy nonce 值                      |

---

## 主题系统

### 内置预设

PrimeVue v4 提供三种开箱即用的主题预设：

| 预设       | 安装路径                  | 风格                   |
| -------- | --------------------- | -------------------- |
| **Aura** | @primevue/themes/aura | PrimeTek 自研现代风格，色调中性 |
| **Lara** | @primevue/themes/lara | Bootstrap 风格衍生，亲切感强  |
| **Nora** | @primevue/themes/nora | 企业级扁平风格，结构感强         |

### 设计令牌三层架构

```
Primitive 令牌（基础色板）
  └── 如 blue-500、surface-200
Semantic 令牌（语义映射）
  └── 如 primary.color → {blue.500}
Component 令牌（组件专属）
  └── 如 button.background → {primary.color}

```

CSS 变量命名规则：`--p-{组件}-{属性}`，如 `--p-button-background`。

### definePreset — 扩展自定义主题

```typescript
import { definePreset } from '@primevue/themes'
import Aura from '@primevue/themes/aura'

const MyPreset = definePreset(Aura, {
  // 覆盖 Semantic 令牌：将主色改为靛蓝色系
  semantic: {
    primary: {
      50:  '{indigo.50}',
      100: '{indigo.100}',
      200: '{indigo.200}',
      300: '{indigo.300}',
      400: '{indigo.400}',
      500: '{indigo.500}',
      600: '{indigo.600}',
      700: '{indigo.700}',
      800: '{indigo.800}',
      900: '{indigo.900}',
      950: '{indigo.950}'
    },
    colorScheme: {
      light: {
        primary: {
          color: '{primary.500}',
          contrastColor: '#ffffff',
          hoverColor: '{primary.600}',
          activeColor: '{primary.700}'
        },
        surface: {
          0:   '#ffffff',
          50:  '{zinc.50}',
          100: '{zinc.100}',
          200: '{zinc.200}',
          300: '{zinc.300}',
          400: '{zinc.400}',
          500: '{zinc.500}',
          600: '{zinc.600}',
          700: '{zinc.700}',
          800: '{zinc.800}',
          900: '{zinc.900}',
          950: '{zinc.950}'
        }
      },
      dark: {
        primary: {
          color: '{primary.400}',
          contrastColor: '{surface.900}',
          hoverColor: '{primary.300}',
          activeColor: '{primary.200}'
        }
      }
    }
  },
  // 覆盖 Component 令牌：自定义按钮样式
  components: {
    button: {
      colorScheme: {
        light: {
          root: {
            background: '{primary.500}',
            hoverBackground: '{primary.600}',
            color: '#ffffff'
          }
        }
      }
    }
  }
})

export default MyPreset

```

在 `main.ts` 中引用：

```typescript
app.use(PrimeVue, {
  theme: { preset: MyPreset }
})

```

### 运行时切换主题

```typescript
import { usePreset, updatePreset } from '@primevue/themes'
import Lara from '@primevue/themes/lara'

// 切换到 Lara 预设
usePreset(Lara)

// 动态更新部分令牌（不切换预设）
updatePreset({
  semantic: {
    primary: {
      500: '#22c55e'
    }
  }
})

```

### 暗色模式

```typescript
// 方式一：跟随系统
app.use(PrimeVue, {
  theme: { preset: Aura, options: { darkModeSelector: 'system' } }
})

// 方式二：手动切换 CSS 类
app.use(PrimeVue, {
  theme: { preset: Aura, options: { darkModeSelector: '.dark' } }
})

// 在组件中切换
document.documentElement.classList.toggle('dark')

```

---

## PassThrough (PT) API

PassThrough API 允许将自定义属性、类名、样式注入到组件内部任意 DOM 节点，无需覆盖 CSS 变量。

### 全局 PT 配置

```typescript
app.use(PrimeVue, {
  theme: { preset: Aura },
  pt: {
    button: {
      root: { class: 'font-bold' },
      label: { class: 'tracking-wide' }
    },
    datatable: {
      root: { class: 'border rounded-lg' },
      thead: { class: 'bg-gray-50' }
    }
  }
})

```

### 组件级 PT

```vue
<Button
  label="提交"
  :pt="{
    root: { class: 'my-custom-btn', 'data-testid': 'submit-btn' },
    label: { style: 'letter-spacing: 0.1em' }
  }"
/>

```

### PT 合并策略

当同时存在全局 PT 和组件级 PT 时，默认后者覆盖前者。可通过 `ptOptions` 配置合并策略：

```typescript
app.use(PrimeVue, {
  ptOptions: {
    mergeSections: true,    // 合并各 section 的类名（而非覆盖）
    mergeProps: true        // 合并属性（而非覆盖）
  }
})

```

### 无样式（Unstyled）模式

完全移除 PrimeVue 内置样式，结合 Tailwind CSS 使用：

```typescript
app.use(PrimeVue, {
  unstyled: true,
  pt: {
    button: {
      root: { class: 'px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors' }
    }
  }
})

```

---

## Nuxt 3 集成

```bash
npm install primevue @primevue/themes
npm install -D @primevue/nuxt-module

```

```typescript
// nuxt.config.ts
import Aura from '@primevue/themes/aura'

export default defineNuxtConfig({
  modules: ['@primevue/nuxt-module'],

  primevue: {
    autoImport: true,  // 自动注册所有组件（默认开启，支持 Tree-shaking）
    options: {
      theme: {
        preset: Aura,
        options: {
          darkModeSelector: '.dark'
        }
      },
      ripple: true
    },
    // 仅引入指定组件（autoImport: false 时生效）
    components: {
      include: ['Button', 'DataTable', 'Dialog', 'InputText', 'Select']
    }
  }
})

```

---

## 常用组件 API

### Button

```vue
<Button
  label="提交"
  icon="pi pi-check"
  icon-pos="right"
  severity="primary"
  :loading="isLoading"
  @click="handleClick"
/>

```

| 属性            | 类型               | 默认值       | 说明                            |           |          |        |          |            |
| ------------- | ---------------- | --------- | ----------------------------- | --------- | -------- | ------ | -------- | ---------- |
| label         | string           | —         | 按钮文字                          |           |          |        |          |            |
| icon          | string           | —         | PrimeIcons 图标类名，如 pi pi-check |           |          |        |          |            |
| iconPos       | string           | 'left'    | 图标位置：'left' \| 'right'        | 'top'     | 'bottom' |        |          |            |
| severity      | string           | 'primary' | 风格：'primary' \| 'secondary'   | 'success' | 'info'   | 'warn' | 'danger' | 'contrast' |
| raised        | boolean          | false     | 添加阴影                          |           |          |        |          |            |
| rounded       | boolean          | false     | 圆角全圆                          |           |          |        |          |            |
| text          | boolean          | false     | 文字按钮，无背景                      |           |          |        |          |            |
| outlined      | boolean          | false     | 描边按钮                          |           |          |        |          |            |
| link          | boolean          | false     | 链接样式                          |           |          |        |          |            |
| size          | string           | —         | 'small' \| 'large'            |           |          |        |          |            |
| loading       | boolean          | false     | 显示加载状态                        |           |          |        |          |            |
| loadingIcon   | string           | —         | 加载状态图标类名                      |           |          |        |          |            |
| disabled      | boolean          | false     | 禁用                            |           |          |        |          |            |
| fluid         | boolean          | false     | 撑满父容器宽度                       |           |          |        |          |            |
| badge         | string           | —         | 徽标内容                          |           |          |        |          |            |
| badgeSeverity | string           | —         | 徽标风格                          |           |          |        |          |            |
| as            | string/Component | 'button'  | 渲染元素类型，可传 'a' 或路由组件           |           |          |        |          |            |
| asChild       | boolean          | false     | 将样式传给子元素（headless）            |           |          |        |          |            |

| 插槽          | 说明             |
| ----------- | -------------- |
| default     | 自定义内容，替换 label |
| icon        | 自定义图标          |
| loadingicon | 自定义加载图标        |

---

### InputText

```vue
<InputText v-model="value" placeholder="请输入..." size="large" fluid />

```

| 属性         | 类型      | 默认值   | 说明                                       |
| ---------- | ------- | ----- | ---------------------------------------- |
| modelValue | string  | —     | v-model 绑定值                              |
| size       | string  | —     | 'small' \| 'large'                       |
| variant    | string  | —     | 'outlined' \| 'filled'，覆盖全局 inputVariant |
| fluid      | boolean | false | 宽度 100%                                  |
| invalid    | boolean | false | 错误状态样式                                   |
| disabled   | boolean | false | 禁用                                       |

| 事件                | 说明  |
| ----------------- | --- |
| update:modelValue | 值变化 |

---

### Select（v3 的 Dropdown）

```vue
<Select
  v-model="selected"
  :options="cities"
  option-label="name"
  option-value="code"
  placeholder="请选择城市"
  filter
  fluid
/>

```

| 属性                     | 类型              | 默认值    | 说明                    |
| ---------------------- | --------------- | ------ | --------------------- |
| modelValue             | any             | —      | 选中值                   |
| options                | array           | —      | 选项数组                  |
| optionLabel            | string/Function | —      | 选项显示字段名或取值函数          |
| optionValue            | string/Function | —      | 选项实际值字段名              |
| optionDisabled         | string/Function | —      | 禁用项字段名                |
| optionGroupLabel       | string          | —      | 分组标签字段名               |
| optionGroupChildren    | string          | —      | 分组子项字段名               |
| placeholder            | string          | —      | 占位文字                  |
| filter                 | boolean         | false  | 启用搜索过滤                |
| filterPlaceholder      | string          | —      | 搜索框占位文字               |
| loading                | boolean         | false  | 加载状态                  |
| disabled               | boolean         | false  | 禁用                    |
| editable               | boolean         | false  | 允许手动输入                |
| showClear              | boolean         | false  | 显示清除按钮                |
| fluid                  | boolean         | false  | 宽度 100%               |
| invalid                | boolean         | false  | 错误状态样式                |
| checkmark              | boolean         | false  | 选中项显示勾选标记             |
| highlightOnSelect      | boolean         | true   | 选中项高亮                 |
| maxSelectedLabels      | number          | 3      | 最多显示几个标签（MultiSelect） |
| panelClass             | string          | —      | 下拉面板额外 CSS 类          |
| appendTo               | string/Element  | 'body' | 下拉挂载点                 |
| virtualScrollerOptions | object          | —      | 虚拟滚动配置（大数据量）          |

| 插槽          | 说明         |
| ----------- | ---------- |
| value       | 自定义选中值显示区域 |
| option      | 自定义选项渲染    |
| optiongroup | 自定义分组标题    |
| header      | 下拉头部       |
| footer      | 下拉底部       |
| empty       | 无选项时的提示内容  |

| 事件          | 说明                       |
| ----------- | ------------------------ |
| change      | 选项改变，payload: { value }  |
| before-show | 面板显示前                    |
| show        | 面板显示后                    |
| before-hide | 面板隐藏前                    |
| hide        | 面板隐藏后                    |
| filter      | 搜索过滤时，payload: { value } |

---

### DatePicker（v3 的 Calendar）

```vue
<DatePicker
  v-model="date"
  date-format="yy-mm-dd"
  :min-date="minDate"
  :max-date="maxDate"
  show-icon
  show-button-bar
/>

```

| 属性             | 类型                   | 默认值        | 说明                     |         |
| -------------- | -------------------- | ---------- | ---------------------- | ------- |
| modelValue     | Date/Date\[\]/object | —          | 绑定值                    |         |
| selectionMode  | string               | 'single'   | 'single' \| 'multiple' | 'range' |
| dateFormat     | string               | 'mm/dd/yy' | 日期格式字符串                |         |
| showTime       | boolean              | false      | 显示时间选择                 |         |
| timeOnly       | boolean              | false      | 仅时间模式                  |         |
| showIcon       | boolean              | false      | 显示日历图标                 |         |
| showButtonBar  | boolean              | false      | 显示今天/清除按钮              |         |
| minDate        | Date                 | —          | 最小可选日期                 |         |
| maxDate        | Date                 | —          | 最大可选日期                 |         |
| disabledDates  | Date\[\]             | —          | 禁用日期列表                 |         |
| disabledDays   | number\[\]           | —          | 禁用星期几（0=周日）            |         |
| numberOfMonths | number               | 1          | 同时显示月份数                |         |
| inline         | boolean              | false      | 内联展示，不作为弹层             |         |
| fluid          | boolean              | false      | 宽度 100%                |         |
| disabled       | boolean              | false      | 禁用                     |         |

---

### DataTable

DataTable 是功能最丰富的组件，支持排序、筛选、分页、行选择、行展开、懒加载、虚拟滚动等。

```vue
<DataTable
  :value="products"
  v-model:selection="selectedProducts"
  v-model:filters="filters"
  selection-mode="multiple"
  data-key="id"
  :paginator="true"
  :rows="10"
  :rows-per-page-options="[5, 10, 25, 50]"
  sort-mode="multiple"
  filter-display="row"
  :loading="loading"
  :lazy="true"
  :total-records="totalRecords"
  @page="onPage"
  @sort="onSort"
  @filter="onFilter"
>
  <template #header>
    <div class="flex justify-between">
      <span>产品列表</span>
      <InputText v-model="filters['global'].value" placeholder="全局搜索" />
    </div>
  </template>

  <Column selection-mode="multiple" style="width: 3rem" />
  <Column field="name" header="名称" sortable />
  <Column field="price" header="价格" sortable>
    <template #body="{ data }">
      ¥{{ data.price.toFixed(2) }}
    </template>
  </Column>
  <Column field="status" header="状态" filter-field="status" :show-filter-menu="false">
    <template #filter="{ filterModel, filterCallback }">
      <Select
        v-model="filterModel.value"
        :options="statuses"
        placeholder="筛选状态"
        @change="filterCallback()"
      />
    </template>
  </Column>
</DataTable>

```

**DataTable 属性（常用）**

| 属性                        | 类型         | 默认值      | 说明                                            |        |
| ------------------------- | ---------- | -------- | --------------------------------------------- | ------ |
| value                     | array      | —        | 数据源                                           |        |
| dataKey                   | string     | —        | 行唯一标识字段（选择/展开等功能必填）                           |        |
| selection                 | any        | —        | 选中行，配合 v-model:selection                      |        |
| selectionMode             | string     | —        | 'single' \| 'multiple'                        |        |
| metaKeySelection          | boolean    | false    | 是否需要按 Meta 键多选                                |        |
| paginator                 | boolean    | false    | 启用分页                                          |        |
| rows                      | number     | —        | 每页行数                                          |        |
| rowsPerPageOptions        | number\[\] | —        | 每页行数选项                                        |        |
| paginatorPosition         | string     | 'bottom' | 'top' \| 'bottom'                             | 'both' |
| currentPageReportTemplate | string     | —        | 分页报告模板，如 '第 {currentPage} 页，共 {totalPages} 页' |        |
| totalRecords              | number     | —        | 总记录数（懒加载必填）                                   |        |
| lazy                      | boolean    | false    | 懒加载模式（分页/排序/筛选由外部处理）                          |        |
| loading                   | boolean    | false    | 加载状态                                          |        |
| sortField                 | string     | —        | 初始排序字段                                        |        |
| sortOrder                 | number     | —        | 初始排序方向：1 升序，\-1 降序                            |        |
| sortMode                  | string     | 'single' | 'single' \| 'multiple'                        |        |
| removableSort             | boolean    | false    | 允许取消排序                                        |        |
| multiSortMeta             | array      | —        | 多列排序元数据                                       |        |
| filters                   | object     | —        | 筛选对象，配合 v-model:filters                       |        |
| filterDisplay             | string     | —        | 'menu' \| 'row'                               |        |
| globalFilterFields        | string\[\] | —        | 全局搜索覆盖字段                                      |        |
| expandedRows              | array      | —        | 展开的行，配合 v-model:expandedRows                  |        |
| rowExpansionTemplate      | —          | —        | 行展开内容（使用插槽）                                   |        |
| frozenColumns             | number     | —        | 冻结左侧列数                                        |        |
| scrollable                | boolean    | false    | 启用滚动                                          |        |
| scrollHeight              | string     | —        | 内容区滚动高度，如 '400px' \| 'flex'                   |        |
| virtualScrollerOptions    | object     | —        | 虚拟滚动配置                                        |        |
| editMode                  | string     | —        | 'cell' \| 'row' 行内编辑                          |        |
| size                      | string     | —        | 'small' \| 'large'                            |        |
| showGridlines             | boolean    | false    | 显示表格线                                         |        |
| stripedRows               | boolean    | false    | 隔行变色                                          |        |
| tableStyle                | string     | —        | table 元素 style                                |        |
| tableClass                | string     | —        | table 元素额外 CSS 类                              |        |

**DataTable 事件**

| 事件                 | 说明                                          |
| ------------------ | ------------------------------------------- |
| page               | 翻页，payload: PageState                       |
| sort               | 排序，payload: SortEvent                       |
| filter             | 筛选，payload: FilterEvent                     |
| row-click          | 点击行，payload: { originalEvent, data, index } |
| row-dblclick       | 双击行                                         |
| row-select         | 选中行                                         |
| row-unselect       | 取消选中行                                       |
| row-expand         | 展开行                                         |
| row-collapse       | 折叠行                                         |
| cell-edit-complete | 单元格编辑完成                                     |
| row-edit-save      | 行编辑保存                                       |
| row-edit-cancel    | 行编辑取消                                       |

**DataTable 插槽**

| 插槽             | 说明                       |
| -------------- | ------------------------ |
| header         | 表格头部                     |
| footer         | 表格底部                     |
| loading        | 加载状态内容                   |
| empty          | 无数据时内容                   |
| paginatorstart | 分页器左侧内容                  |
| paginatorend   | 分页器右侧内容                  |
| expansion      | 行展开内容，接收 { data, index } |
| groupheader    | 行分组头部                    |
| groupfooter    | 行分组尾部                    |

**Column 属性**

| 属性              | 类型      | 默认值    | 说明                         |
| --------------- | ------- | ------ | -------------------------- |
| field           | string  | —      | 对应数据字段                     |
| header          | string  | —      | 列标题                        |
| sortable        | boolean | false  | 允许排序                       |
| sortField       | string  | —      | 排序使用的字段（与 field 不同时）       |
| filter          | boolean | false  | 启用该列过滤                     |
| filterField     | string  | —      | 过滤使用的字段                    |
| showFilterMenu  | boolean | true   | 显示过滤菜单图标                   |
| filterMatchMode | string  | —      | 默认匹配模式                     |
| selectionMode   | string  | —      | 'single' \| 'multiple' 选择列 |
| frozen          | boolean | false  | 冻结该列                       |
| alignFrozen     | string  | 'left' | 冻结位置：'left' \| 'right'     |
| expander        | boolean | false  | 行展开按钮列                     |
| rowspan         | number  | —      | 行合并                        |
| colspan         | number  | —      | 列合并                        |
| style           | string  | —      | 列样式                        |
| class           | string  | —      | 列 CSS 类                    |
| bodyStyle       | string  | —      | body 单元格样式                 |
| bodyClass       | string  | —      | body 单元格 CSS 类             |
| headerStyle     | string  | —      | 表头单元格样式                    |
| headerClass     | string  | —      | 表头单元格 CSS 类                |
| pt              | object  | —      | PassThrough 配置             |

**Column 插槽**

| 插槽          | 说明                                 |
| ----------- | ---------------------------------- |
| body        | 自定义单元格内容，接收 { data, field, index } |
| header      | 自定义列标题                             |
| footer      | 自定义列底部                             |
| filter      | 自定义过滤元素                            |
| filterclear | 清除过滤按钮内容                           |
| filterapply | 应用过滤按钮内容                           |
| editor      | 行内编辑元素                             |

**筛选初始化示例**

```typescript
import { FilterMatchMode } from '@primevue/core/api'

const filters = ref({
  global:   { value: null, matchMode: FilterMatchMode.CONTAINS },
  name:     { value: null, matchMode: FilterMatchMode.STARTS_WITH },
  status:   { value: null, matchMode: FilterMatchMode.EQUALS },
  price:    { value: null, matchMode: FilterMatchMode.GREATER_THAN }
})

```

可用 `FilterMatchMode` 值：`STARTS_WITH`、`CONTAINS`、`NOT_CONTAINS`、`ENDS_WITH`、`EQUALS`、`NOT_EQUALS`、`IN`、`LESS_THAN`、`LESS_THAN_OR_EQUAL_TO`、`GREATER_THAN`、`GREATER_THAN_OR_EQUAL_TO`、`BETWEEN`、`DATE_IS`、`DATE_IS_NOT`、`DATE_BEFORE`、`DATE_AFTER`。

---

### Dialog

```vue
<Button label="打开" @click="visible = true" />

<Dialog
  v-model:visible="visible"
  header="确认操作"
  :modal="true"
  :draggable="true"
  :closable="true"
  :style="{ width: '30rem' }"
  :breakpoints="{ '960px': '75vw', '641px': '100vw' }"
>
  <p>确认要执行此操作吗？</p>
  <template #footer>
    <Button label="取消" text @click="visible = false" />
    <Button label="确认" @click="onConfirm" />
  </template>
</Dialog>

```

| 属性              | 类型             | 默认值      | 说明                            |          |        |         |    |
| --------------- | -------------- | -------- | ----------------------------- | -------- | ------ | ------- | -- |
| visible         | boolean        | —        | 显示状态，配合 v-model:visible       |          |        |         |    |
| header          | string         | —        | 标题文字                          |          |        |         |    |
| modal           | boolean        | true     | 是否显示遮罩                        |          |        |         |    |
| closable        | boolean        | true     | 显示关闭按钮                        |          |        |         |    |
| closeOnEscape   | boolean        | true     | 按 Esc 关闭                      |          |        |         |    |
| dismissableMask | boolean        | false    | 点击遮罩关闭                        |          |        |         |    |
| draggable       | boolean        | true     | 允许拖拽                          |          |        |         |    |
| resizable       | boolean        | true     | 允许调整大小                        |          |        |         |    |
| maximizable     | boolean        | false    | 显示最大化按钮                       |          |        |         |    |
| position        | string         | 'center' | 位置：'center' \| 'top'          | 'bottom' | 'left' | 'right' | 四角 |
| style           | object         | —        | 对话框 style                     |          |        |         |    |
| class           | string         | —        | 对话框额外 CSS 类                   |          |        |         |    |
| contentStyle    | object         | —        | 内容区 style                     |          |        |         |    |
| contentClass    | string         | —        | 内容区 CSS 类                     |          |        |         |    |
| breakpoints     | object         | —        | 响应式宽度断点，如 { '960px': '75vw' } |          |        |         |    |
| appendTo        | string/Element | 'body'   | 挂载目标                          |          |        |         |    |
| blockScroll     | boolean        | false    | 打开时锁定 body 滚动                 |          |        |         |    |
| keepInViewport  | boolean        | true     | 拖拽时保持在视口内                     |          |        |         |    |

| 插槽           | 说明          |
| ------------ | ----------- |
| default      | 对话框内容       |
| header       | 自定义标题区域     |
| footer       | 底部按钮区域      |
| closeicon    | 自定义关闭图标     |
| maximizeicon | 自定义最大化图标    |
| container    | 完全接管对话框外层容器 |

| 事件         | 说明      |
| ---------- | ------- |
| show       | 对话框显示后  |
| hide       | 对话框关闭后  |
| after-hide | 关闭动画完成后 |
| maximize   | 最大化切换   |
| dragend    | 拖拽结束    |

---

### Drawer（v3 的 Sidebar）

```vue
<Drawer v-model:visible="drawerVisible" header="菜单" position="left">
  <nav>
    <ul>
      <li>首页</li>
      <li>关于</li>
    </ul>
  </nav>
</Drawer>

```

| 属性            | 类型      | 默认值    | 说明                |       |          |
| ------------- | ------- | ------ | ----------------- | ----- | -------- |
| visible       | boolean | —      | 显示状态              |       |          |
| header        | string  | —      | 标题                |       |          |
| position      | string  | 'left' | 'left' \| 'right' | 'top' | 'bottom' |
| modal         | boolean | true   | 显示遮罩              |       |          |
| dismissable   | boolean | true   | 点击遮罩关闭            |       |          |
| showCloseIcon | boolean | true   | 显示关闭按钮            |       |          |
| closeOnEscape | boolean | true   | Esc 关闭            |       |          |
| style         | object  | —      | 面板 style          |       |          |
| blockScroll   | boolean | false  | 打开时锁定滚动           |       |          |
| full-screen   | boolean | false  | 全屏模式              |       |          |

| 插槽        | 说明     |
| --------- | ------ |
| default   | 内容     |
| header    | 自定义标题  |
| container | 接管整个容器 |

---

### Toast 服务

**注册服务**

```typescript
// main.ts
import ToastService from 'primevue/toastservice'
app.use(ToastService)

```

**放置 Toast 容器**（通常在 App.vue）

```vue
<template>
  <Toast />
  <RouterView />
</template>

```

**在组件中使用**

```typescript
import { useToast } from 'primevue/usetoast'

const toast = useToast()

// 各种类型
toast.add({ severity: 'success', summary: '成功', detail: '操作已完成', life: 3000 })
toast.add({ severity: 'info',    summary: '提示', detail: '这是一条信息' })
toast.add({ severity: 'warn',    summary: '警告', detail: '请注意此操作' })
toast.add({ severity: 'error',   summary: '错误', detail: '操作失败，请重试', sticky: true })
toast.add({ severity: 'secondary', summary: '次要', detail: '次要消息' })
toast.add({ severity: 'contrast', summary: '对比', detail: '对比色消息' })

// 清除
toast.remove(toastInstance)  // 移除指定
toast.removeGroup('myGroup') // 移除指定分组
toast.removeAllGroups()      // 移除所有

```

**Toast 消息选项**

| 选项       | 类型      | 默认值    | 说明                        |        |         |             |            |
| -------- | ------- | ------ | ------------------------- | ------ | ------- | ----------- | ---------- |
| severity | string  | 'info' | 'success' \| 'info'       | 'warn' | 'error' | 'secondary' | 'contrast' |
| summary  | string  | —      | 标题                        |        |         |             |            |
| detail   | string  | —      | 详细内容                      |        |         |             |            |
| life     | number  | 3000   | 自动关闭时间（毫秒），0 或不设表示不自动关闭   |        |         |             |            |
| sticky   | boolean | false  | 持久显示，不自动关闭                |        |         |             |            |
| closable | boolean | true   | 显示关闭按钮                    |        |         |             |            |
| group    | string  | —      | 分组名，配合 Toast 组件的 group 属性 |        |         |             |            |
| icon     | string  | —      | 自定义图标类名                   |        |         |             |            |

**Toast 组件属性**

| 属性          | 类型     | 默认值         | 说明                         |             |               |                 |                |          |
| ----------- | ------ | ----------- | -------------------------- | ----------- | ------------- | --------------- | -------------- | -------- |
| position    | string | 'top-right' | 'top-left' \| 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right' | 'center' |
| group       | string | —           | 对应特定分组消息                   |             |               |                 |                |          |
| baseZIndex  | number | 0           | 基础层叠 z-index               |             |               |                 |                |          |
| breakpoints | object | —           | 响应式宽度断点                    |             |               |                 |                |          |
| pt          | object | —           | PassThrough 配置             |             |               |                 |                |          |

---

### ConfirmDialog / ConfirmPopup 服务

**注册服务**

```typescript
// main.ts
import ConfirmationService from 'primevue/confirmationservice'
app.use(ConfirmationService)

```

**放置容器**

```vue
<ConfirmDialog />
<!-- 或气泡确认 -->
<ConfirmPopup />

```

**在组件中使用**

```typescript
import { useConfirm } from 'primevue/useconfirm'

const confirm = useConfirm()

// 对话框确认
confirm.require({
  message:  '确定要删除吗？此操作不可逆。',
  header:   '删除确认',
  icon:     'pi pi-exclamation-triangle',
  rejectLabel:   '取消',
  acceptLabel:   '确认删除',
  rejectProps:   { label: '取消', severity: 'secondary', outlined: true },
  acceptProps:   { label: '确认删除', severity: 'danger' },
  accept: () => {
    toast.add({ severity: 'info', summary: '已删除', life: 3000 })
  },
  reject: () => {
    toast.add({ severity: 'warn', summary: '已取消', life: 3000 })
  }
})

// 气泡确认（需要目标元素）
confirm.require({
  target:  event.currentTarget,
  message: '确认删除？',
  icon:    'pi pi-info-circle',
  accept:  () => doDelete()
})

```

---

### Popover（v3 的 OverlayPanel）

```vue
<Button label="更多信息" @click="pop.toggle($event)" />
<Popover ref="pop">
  <div class="p-4">
    <p>这是弹出内容</p>
  </div>
</Popover>

```

```typescript
const pop = ref()

// 方法
pop.value.show(event)   // 显示
pop.value.hide()        // 隐藏
pop.value.toggle(event) // 切换

```

| 属性            | 类型             | 默认值    | 说明             |
| ------------- | -------------- | ------ | -------------- |
| dismissable   | boolean        | true   | 点击外部关闭         |
| closeOnEscape | boolean        | true   | Esc 关闭         |
| appendTo      | string/Element | 'body' | 挂载目标           |
| style         | object         | —      | 面板 style       |
| class         | string         | —      | 面板额外 CSS 类     |
| pt            | object         | —      | PassThrough 配置 |

---

### Tabs（v3 的 TabView）

```vue
<Tabs value="0">
  <TabList>
    <Tab value="0">首页</Tab>
    <Tab value="1">关于</Tab>
    <Tab value="2">联系</Tab>
  </TabList>
  <TabPanels>
    <TabPanel value="0">
      <p>首页内容</p>
    </TabPanel>
    <TabPanel value="1">
      <p>关于内容</p>
    </TabPanel>
  </TabPanels>
</Tabs>

```

| 属性（Tabs）      | 类型            | 默认值   | 说明                           |
| ------------- | ------------- | ----- | ---------------------------- |
| value         | string/number | —     | 当前激活 Tab 的值，配合 v-model:value |
| lazy          | boolean       | false | 懒渲染非激活 Tab 内容                |
| scrollable    | boolean       | false | Tab 列表可横向滚动                  |
| selectOnFocus | boolean       | false | 键盘聚焦时即激活                     |

---

### Accordion

```vue
<Accordion value="0">
  <AccordionPanel value="0">
    <AccordionHeader>标题一</AccordionHeader>
    <AccordionContent>
      <p>内容一</p>
    </AccordionContent>
  </AccordionPanel>
  <AccordionPanel value="1">
    <AccordionHeader>标题二</AccordionHeader>
    <AccordionContent>
      <p>内容二</p>
    </AccordionContent>
  </AccordionPanel>
</Accordion>

```

| 属性（Accordion） | 类型                | 默认值   | 说明                        |
| ------------- | ----------------- | ----- | ------------------------- |
| value         | string/string\[\] | —     | 展开项，multiple 为 true 时可传数组 |
| multiple      | boolean           | false | 允许同时展开多项                  |
| lazy          | boolean           | false | 懒渲染折叠内容                   |
| collapseIcon  | string            | —     | 折叠状态图标                    |
| expandIcon    | string            | —     | 展开状态图标                    |

---

### InputNumber

```vue
<InputNumber
  v-model="price"
  prefix="¥"
  :min="0"
  :max="9999"
  :min-fraction-digits="2"
  :max-fraction-digits="2"
  :use-grouping="true"
  locale="zh-CN"
  mode="currency"
  currency="CNY"
  fluid
/>

```

| 属性                | 类型      | 默认值       | 说明                            |            |
| ----------------- | ------- | --------- | ----------------------------- | ---------- |
| modelValue        | number  | —         | v-model 绑定值                   |            |
| mode              | string  | 'decimal' | 'decimal' \| 'currency'       |            |
| locale            | string  | —         | 使用的区域设置                       |            |
| currency          | string  | —         | 货币代码，如 'CNY'（mode=currency 时） |            |
| prefix            | string  | —         | 前缀文本                          |            |
| suffix            | string  | —         | 后缀文本                          |            |
| min               | number  | —         | 最小值                           |            |
| max               | number  | —         | 最大值                           |            |
| step              | number  | 1         | 步进值                           |            |
| showButtons       | boolean | false     | 显示加减按钮                        |            |
| buttonLayout      | string  | 'stacked' | 'stacked' \| 'horizontal'     | 'vertical' |
| useGrouping       | boolean | true      | 使用千位分隔符                       |            |
| minFractionDigits | number  | —         | 最少小数位数                        |            |
| maxFractionDigits | number  | —         | 最多小数位数                        |            |
| disabled          | boolean | false     | 禁用                            |            |
| readonly          | boolean | false     | 只读                            |            |
| invalid           | boolean | false     | 错误状态                          |            |
| fluid             | boolean | false     | 宽度 100%                       |            |

---

### AutoComplete

```vue
<AutoComplete
  v-model="value"
  :suggestions="items"
  @complete="search"
  option-label="name"
  force-selection
  :multiple="false"
  fluid
>
  <template #option="{ option }">
    <div class="flex items-center gap-2">
      <img :src="option.avatar" class="w-6 h-6 rounded-full" />
      <span>{{ option.name }}</span>
    </div>
  </template>
</AutoComplete>

```

```typescript
const search = (event: { query: string }) => {
  items.value = allItems.filter(item =>
    item.name.toLowerCase().includes(event.query.toLowerCase())
  )
}

```

| 属性                     | 类型              | 默认值     | 说明                        |
| ---------------------- | --------------- | ------- | ------------------------- |
| modelValue             | any             | —       | v-model 绑定值               |
| suggestions            | array           | —       | 匹配建议列表                    |
| optionLabel            | string/Function | —       | 显示字段                      |
| optionGroupLabel       | string          | —       | 分组标签字段                    |
| optionGroupChildren    | string          | —       | 分组子项字段                    |
| multiple               | boolean         | false   | 多选 tag 模式                 |
| typeahead              | boolean         | true    | 自动完成打字；设 false 可做纯 tag 输入 |
| forceSelection         | boolean         | false   | 只允许从建议中选择                 |
| minLength              | number          | 1       | 触发搜索的最少字符数                |
| delay                  | number          | 300     | 输入到触发 complete 事件的延迟（毫秒）  |
| disabled               | boolean         | false   | 禁用                        |
| fluid                  | boolean         | false   | 宽度 100%                   |
| dropdown               | boolean         | false   | 显示下拉触发按钮                  |
| dropdownMode           | string          | 'blank' | 点击下拉按钮的搜索模式               |
| virtualScrollerOptions | object          | —       | 大数据量虚拟滚动                  |

| 事件            | 说明                 |
| ------------- | ------------------ |
| complete      | 输入时触发，接收 { query } |
| item-select   | 选中建议项，接收 { value } |
| item-unselect | 取消选中（多选模式）         |
| change        | 值变化                |
| focus / blur  | 聚焦/失焦              |

---

### FileUpload

```vue
<FileUpload
  name="file"
  url="/api/upload"
  :multiple="true"
  accept="image/*"
  :max-file-size="1000000"
  :auto="false"
  @upload="onUpload"
  @before-upload="onBeforeUpload"
  @error="onError"
/>

```

| 属性               | 类型      | 默认值        | 说明                                |
| ---------------- | ------- | ---------- | --------------------------------- |
| name             | string  | —          | 表单字段名                             |
| url              | string  | —          | 上传接口地址                            |
| method           | string  | 'POST'     | HTTP 方法                           |
| multiple         | boolean | false      | 允许多选                              |
| accept           | string  | —          | 允许的文件类型，如 'image/\*,.pdf'         |
| disabled         | boolean | false      | 禁用                                |
| auto             | boolean | false      | 选文件后自动上传                          |
| maxFileSize      | number  | —          | 最大文件大小（字节）                        |
| fileLimit        | number  | —          | 最多文件数                             |
| withCredentials  | boolean | false      | 携带凭证（Cookie）                      |
| mode             | string  | 'advanced' | 'advanced'（完整 UI）\| 'basic'（简单按钮） |
| customUpload     | boolean | false      | 使用自定义上传逻辑                         |
| showUploadButton | boolean | true       | 显示上传按钮                            |
| showCancelButton | boolean | true       | 显示取消按钮                            |
| previewWidth     | number  | 50         | 预览图宽度（px）                         |
| chooseLabel      | string  | '选择'       | 选择按钮文字                            |
| uploadLabel      | string  | '上传'       | 上传按钮文字                            |
| cancelLabel      | string  | '取消'       | 取消按钮文字                            |

| 事件            | 说明                               |
| ------------- | -------------------------------- |
| before-upload | 上传前，可修改 XmlHttpRequest           |
| upload        | 上传完成，接收 { files, xhr }           |
| error         | 上传失败                             |
| clear         | 文件列表清空                           |
| select        | 文件选择，接收 { files, originalEvent } |
| remove        | 移除文件                             |
| uploader      | 自定义上传处理（customUpload: true 时）    |

---

### Menu / MenuBar / TieredMenu / ContextMenu

```vue
<!-- Menu（弹出式） -->
<Button label="操作" @click="menu.toggle($event)" />
<Menu ref="menu" :model="menuItems" :popup="true" />

<!-- Menubar（顶部导航） -->
<Menubar :model="navItems">
  <template #start>
    <img src="/logo.svg" class="h-8" />
  </template>
  <template #end>
    <Button label="登录" />
  </template>
</Menubar>

<!-- ContextMenu（右键菜单） -->
<ContextMenu ref="cm" :model="contextItems" />
<div @contextmenu="cm.show($event)">右键点击此区域</div>

```

菜单 `model` 的数据结构：

```typescript
const menuItems = ref([
  {
    label: '文件',
    icon: 'pi pi-file',
    items: [
      { label: '新建', icon: 'pi pi-plus', command: () => createFile() },
      { label: '打开', icon: 'pi pi-folder-open', command: () => openFile() },
      { separator: true },
      { label: '退出', icon: 'pi pi-sign-out', command: () => exit() }
    ]
  },
  {
    label: '外部链接',
    icon: 'pi pi-external-link',
    url: 'https://example.com',
    target: '_blank'
  },
  {
    label: '路由',
    icon: 'pi pi-home',
    route: '/home'  // 配合 vue-router 使用
  }
])

```

菜单项字段：

| 字段            | 类型            | 说明                           |
| ------------- | ------------- | ---------------------------- |
| label         | string        | 菜单项文字                        |
| icon          | string        | 图标类名                         |
| command       | Function      | 点击回调                         |
| url           | string        | 外部链接地址                       |
| target        | string        | 链接打开方式                       |
| route         | string/object | vue-router 路由路径或对象           |
| items         | array         | 子菜单（TieredMenu/Menubar 支持多层） |
| separator     | boolean       | 是否为分隔线                       |
| disabled      | boolean       | 禁用该菜单项                       |
| visible       | boolean       | 是否可见                         |
| badge         | string        | 徽标文字                         |
| badgeSeverity | string        | 徽标风格                         |
| class         | string        | 额外 CSS 类                     |
| style         | object        | 内联样式                         |
| shortcut      | string        | 快捷键提示文字（仅显示，不绑定）             |

---

### Stepper（v3 的 Steps）

```vue
<Stepper v-model:value="activeStep" linear>
  <StepList>
    <Step value="1">账户信息</Step>
    <Step value="2">个人资料</Step>
    <Step value="3">完成</Step>
  </StepList>
  <StepPanels>
    <StepPanel value="1" v-slot="{ activateCallback }">
      <div>步骤一内容</div>
      <Button label="下一步" @click="activateCallback('2')" />
    </StepPanel>
    <StepPanel value="2" v-slot="{ activateCallback }">
      <div>步骤二内容</div>
      <Button label="上一步" @click="activateCallback('1')" />
      <Button label="下一步" @click="activateCallback('3')" />
    </StepPanel>
    <StepPanel value="3">
      <div>完成！</div>
    </StepPanel>
  </StepPanels>
</Stepper>

```

---

### Chart

基于 Chart.js，需额外安装：

```bash
npm install chart.js

```

```vue
<Chart type="bar" :data="chartData" :options="chartOptions" style="height: 400px" />

```

```typescript
const chartData = ref({
  labels: ['一月', '二月', '三月', '四月'],
  datasets: [
    {
      label: '销售额',
      data: [65, 59, 80, 81],
      backgroundColor: ['rgba(255, 99, 132, 0.2)', 'rgba(255, 159, 64, 0.2)']
    }
  ]
})

const chartOptions = ref({
  responsive: true,
  plugins: {
    legend: { position: 'top' }
  }
})

```

| 属性      | 类型     | 默认值 | 说明                   |       |            |         |             |          |           |
| ------- | ------ | --- | -------------------- | ----- | ---------- | ------- | ----------- | -------- | --------- |
| type    | string | —   | 图表类型：'bar' \| 'line' | 'pie' | 'doughnut' | 'radar' | 'polarArea' | 'bubble' | 'scatter' |
| data    | object | —   | Chart.js data 对象     |       |            |         |             |          |           |
| options | object | —   | Chart.js options 对象  |       |            |         |             |          |           |
| plugins | array  | —   | Chart.js 插件数组        |       |            |         |             |          |           |
| width   | number | 300 | 画布宽度                 |       |            |         |             |          |           |
| height  | number | 150 | 画布高度                 |       |            |         |             |          |           |

---

## 表单验证集成

### 与 VeeValidate + Zod 集成

```bash
npm install vee-validate zod @vee-validate/zod

```

```vue
<script setup lang="ts">
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import { z } from 'zod'

const schema = toTypedSchema(z.object({
  username: z.string().min(3, '用户名至少 3 位').max(20),
  email:    z.string().email('邮箱格式不正确'),
  age:      z.number({ required_error: '请填写年龄' }).min(18, '须年满 18 岁')
}))

const { handleSubmit, defineField, errors, isSubmitting } = useForm({
  validationSchema: schema
})

const [username, usernameAttrs] = defineField('username')
const [email, emailAttrs] = defineField('email')
const [age, ageAttrs] = defineField('age')

const onSubmit = handleSubmit(async (values) => {
  console.log('提交值：', values)
})
</script>

<template>
  <form @submit.prevent="onSubmit">
    <div class="flex flex-col gap-1 mb-4">
      <label>用户名</label>
      <InputText v-model="username" v-bind="usernameAttrs" :invalid="!!errors.username" />
      <small class="text-red-500">{{ errors.username }}</small>
    </div>

    <div class="flex flex-col gap-1 mb-4">
      <label>邮箱</label>
      <InputText v-model="email" v-bind="emailAttrs" :invalid="!!errors.email" />
      <small class="text-red-500">{{ errors.email }}</small>
    </div>

    <div class="flex flex-col gap-1 mb-4">
      <label>年龄</label>
      <InputNumber v-model="age" v-bind="ageAttrs" :invalid="!!errors.age" fluid />
      <small class="text-red-500">{{ errors.age }}</small>
    </div>

    <Button type="submit" label="提交" :loading="isSubmitting" />
  </form>
</template>

```

---

## 与 Tailwind CSS 配合

启用 `cssLayer` 使 Tailwind 的工具类可以覆盖 PrimeVue 样式：

```typescript
// main.ts
app.use(PrimeVue, {
  theme: {
    preset: Aura,
    options: {
      cssLayer: {
        name: 'primevue',
        order: 'tailwind-base, primevue, tailwind-utilities'
      }
    }
  }
})

```

```css
/* tailwind.css */
@layer tailwind-base {
  @tailwind base;
}
@layer tailwind-utilities {
  @tailwind utilities;
}

```

---

## 组件完整清单

### v3 → v4 更名对照

| v3 名称         | v4 名称         | 说明       |
| ------------- | ------------- | -------- |
| Calendar      | DatePicker    | 日期/时间选择器 |
| Dropdown      | Select        | 下拉选择     |
| InputSwitch   | ToggleSwitch  | 开关       |
| OverlayPanel  | Popover       | 弹出层      |
| Sidebar       | Drawer        | 侧边抽屉     |
| TabView       | Tabs          | 标签页      |
| InlineMessage | Message       | 内联消息     |
| Steps         | Stepper       | 步骤条      |
| TabMenu       | Tabs（无 Panel） | 标签导航     |

### v4 废弃组件

| 废弃组件                  | 替代方案                                          |
| --------------------- | --------------------------------------------- |
| Chips                 | AutoComplete（multiple: true，typeahead: false） |
| TriStateCheckbox      | Checkbox（indeterminate 属性）                    |
| DataViewLayoutOptions | SelectButton                                  |

### 按分类列举全部组件

**表单**

| 组件            | 说明                  |
| ------------- | ------------------- |
| InputText     | 单行文本输入              |
| Textarea      | 多行文本                |
| InputNumber   | 数字输入，支持格式化          |
| Password      | 密码输入，强度指示           |
| InputMask     | 格式掩码输入              |
| InputOtp      | OTP 验证码输入           |
| AutoComplete  | 自动完成                |
| Select        | 下拉选择（原 Dropdown）    |
| MultiSelect   | 多选下拉                |
| DatePicker    | 日期/时间选择（原 Calendar） |
| CascadeSelect | 级联下拉                |
| Checkbox      | 复选框                 |
| RadioButton   | 单选按钮                |
| ToggleSwitch  | 开关（原 InputSwitch）   |
| ToggleButton  | 切换按钮                |
| SelectButton  | 多按钮单选/多选            |
| Slider        | 滑块                  |
| ColorPicker   | 颜色选择器               |
| Knob          | 旋钮                  |
| Rating        | 评分                  |
| TreeSelect    | 树形选择                |
| FileUpload    | 文件上传                |
| Editor        | 富文本编辑器（基于 Quill）    |

**数据展示**

| 组件              | 说明                 |
| --------------- | ------------------ |
| DataTable       | 数据表格               |
| Column          | 表格列（DataTable 子组件） |
| ColumnGroup     | 列分组                |
| TreeTable       | 树形表格               |
| DataView        | 数据视图（列表/网格切换）      |
| VirtualScroller | 虚拟列表               |
| OrderList       | 可排序列表              |
| PickList        | 穿梭框                |
| Tree            | 树形控件               |
| Timeline        | 时间线                |
| Paginator       | 分页器（独立组件）          |
| Chart           | 图表（基于 Chart.js）    |

**面板**

| 组件              | 说明             |
| --------------- | -------------- |
| Panel           | 可折叠面板容器        |
| Fieldset        | 字段集分组          |
| Card            | 卡片             |
| Accordion       | 手风琴            |
| Tabs            | 标签页（原 TabView） |
| Divider         | 分割线            |
| Splitter        | 可拖拽分割布局        |
| ScrollPanel     | 自定义滚动条面板       |
| DeferredContent | 延迟渲染内容         |
| Toolbar         | 工具栏            |

**覆盖层**

| 组件            | 说明                  |
| ------------- | ------------------- |
| Dialog        | 对话框                 |
| Drawer        | 侧边抽屉（原 Sidebar）     |
| Popover       | 弹出层（原 OverlayPanel） |
| Tooltip       | 文字提示（指令）            |
| ConfirmDialog | 确认对话框               |
| ConfirmPopup  | 确认气泡                |
| DynamicDialog | 动态对话框               |

**消息**

| 组件      | 说明                    |
| ------- | --------------------- |
| Toast   | 轻提示                   |
| Message | 内联消息（原 InlineMessage） |

**菜单**

| 组件          | 说明                  |
| ----------- | ------------------- |
| Menu        | 简单菜单                |
| Menubar     | 顶部菜单栏               |
| TieredMenu  | 多级菜单                |
| ContextMenu | 右键菜单                |
| MegaMenu    | 超级菜单                |
| BreadCrumb  | 面包屑                 |
| PanelMenu   | 侧边多级菜单              |
| Dock        | macOS 风格 Dock 栏     |
| SpeedDial   | 快速拨号浮动按钮组           |
| SplitButton | 分裂按钮                |
| Steps       | 步骤导航（建议迁移到 Stepper） |

**其他**

| 组件/指令             | 说明                        |
| ----------------- | ------------------------- |
| Avatar            | 头像，支持文字/图标/图片             |
| AvatarGroup       | 头像组                       |
| Badge             | 徽标数字                      |
| OverlayBadge      | 覆盖徽标包装器（原 BadgeDirective） |
| Tag               | 标签                        |
| Chip              | 芯片                        |
| ProgressBar       | 进度条                       |
| ProgressSpinner   | 加载旋转圈                     |
| Skeleton          | 骨架屏                       |
| ScrollTop         | 返回顶部按钮                    |
| Image             | 图片（支持预览/旋转/缩放）            |
| Galleria          | 图片画廊                      |
| Carousel          | 轮播图                       |
| BlockUI           | 区域遮罩                      |
| Inplace           | 内联编辑                      |
| MeterGroup        | 分段进度条                     |
| Terminal          | 终端模拟                      |
| v-tooltip         | Tooltip 指令                |
| v-badge           | Badge 指令                  |
| v-ripple          | 水波纹指令                     |
| v-styleclass      | 样式类切换指令                   |
| v-focustrap       | 焦点捕获指令                    |
| v-animateonscroll | 滚动动画指令                    |

---

## 无障碍（Accessibility）

PrimeVue v4 按照 [WAI-ARIA 1.2](https://www.w3.org/TR/wai-aria-1.2/) 规范构建。

- 所有交互组件均内置 `aria-*` 属性
- 支持键盘导航（Tab、方向键、Enter、Space、Esc）
- 提供 `ariaLabel`、`ariaLabelledBy` 等属性供自定义
- 使用 `<PrimeVuePassThrough>` 或 PT API 可进一步定制 aria 属性

---

## 常见踩坑

**1\. v4 不再引入旧版 CSS**

```typescript
// v3 写法（v4 中删除）
import 'primevue/resources/themes/lara-light-blue/theme.css'
import 'primevue/resources/primevue.min.css'

```

v4 通过 `@primevue/themes` 的 JS 对象统一管理主题，无需引入任何 CSS 文件。

**2\. API 路径变更**

```typescript
// v3
import { FilterMatchMode } from 'primevue/api'

// v4
import { FilterMatchMode } from '@primevue/core/api'

```

**3\. `p-fluid` 类废弃**

v3 中包裹 `<div class="p-fluid">` 可使内部组件撑满宽度；v4 中改为在组件上使用 `fluid` prop：

```vue
<!-- v3 -->
<div class="p-fluid">
  <InputText v-model="val" />
</div>

<!-- v4 -->
<InputText v-model="val" fluid />

```

**4\. Dark Mode 与 SSR 水合不匹配**

Nuxt 3 中使用 `darkModeSelector: '.dark'` 并配合 `@nuxtjs/color-mode` 时，确保服务端和客户端的初始类名一致，否则会出现 Hydration Mismatch。

**5\. DataTable 懒加载 totalRecords 必须提前设置**

`lazy: true` 时，分页器需要 `totalRecords` 才能计算页数。初始加载时应在获取第一页数据的同时设置 `totalRecords`。

**6\. Tooltip 指令注册**

使用 `v-tooltip` 前需注册：

```typescript
import Tooltip from 'primevue/tooltip'
app.directive('tooltip', Tooltip)
// 或在 Nuxt 中通过 directives 配置自动注册

```

---

## 最佳实践

**选用 Unstyled 模式 + Tailwind，而非 Styled 模式**：PrimeVue v4 的 Unstyled 模式（`unstyled: true`）允许完全自定义样式，配合 `tailwindcss-primeui` 插件可以用 Tailwind 类名控制组件外观，避免主题覆盖战。Styled 模式适合快速原型，Unstyled 模式适合需要严格设计系统的项目。

**使用 `PassThrough` API 为单个组件实例添加 class，而非全局覆盖 CSS**：通过 `:pt` prop 可以精确控制组件内部 DOM 节点的类名，比写全局 CSS 选择器更可预期且不影响其他组件实例。

```vue
<DataTable :pt="{ root: { class: 'border rounded-lg' }, header: { class: 'bg-gray-50' } }">

```

**DataTable 分页用受控模式（`:rows` \+ `@page`），而非非受控**：非受控模式下，分页状态由组件内部管理，无法与 URL、路由或外部状态同步。受控模式将 `first`、`rows` 状态提升到外部，便于持久化和服务端分页。

**表单组件与 Vee-Validate 或 Vue-Formkit 集成时，使用 `v-bind` 传递错误状态而非包装层**：PrimeVue v4 的表单组件接受 `invalid` prop，直接绑定校验库的错误状态即可，无需额外包装组件。

```vue
<InputText v-model="email" :invalid="!!errors.email" />
<small class="text-red-500">{{ errors.email }}</small>

```

**图标使用 `primeicons` 类名时检查版本兼容性**：PrimeIcons 在大版本更新时会重命名部分图标（如 `pi-home` → `pi-house`），升级后应全量搜索项目中的 `pi-` 类名进行核对。

---

## 常见陷阱

### 陷阱：Styled 模式下自定义 CSS 被覆盖

**现象：** 通过全局 CSS 修改 DataTable 行高或颜色，在开发环境生效，生产构建后失效；或某些状态（hover、selected）样式无法覆盖。

**原因：** PrimeVue Styled 模式的主题 CSS 使用了较高特异性的选择器，全局 `class` 覆盖时特异性不够；生产构建中 CSS 加载顺序可能与开发环境不同。

**解决：** 升级到 Unstyled 模式使用 PT API 控制样式；或用 `:deep()` 穿透 Scoped CSS；或在主题 CSS 后引入自定义 CSS 以保证顺序。

```vue
<style scoped>
:deep(.p-datatable-row-selected) {
  background: #e0f2fe !important;
}
</style>

```

### 陷阱：`v-model` 在 Dialog 内的组件数据不同步

**现象：** Dialog 打开后修改了表单数据，关闭再打开时，数据没有重置或显示了上次的值。

**原因：** Dialog 组件默认在关闭时不销毁内部 DOM（仅隐藏），Vue 组件状态保留，下次打开时仍是上次的值。

**解决：** 使用 `:visible` 控制显隐时，在 `@hide` 事件中手动重置表单数据；或使用 `v-if` 替代 `v-show` 控制 Dialog，每次打开都重新挂载组件。

```vue
<Dialog v-model:visible="showDialog" @hide="resetForm">

```

### 陷阱：DataTable 懒加载时 `totalRecords` 未同步导致分页异常

**现象：** 服务端分页时，分页器显示的总页数不对，或跳转到最后一页后无数据。

**原因：** `lazy: true` 时，DataTable 分页器完全依赖 `totalRecords` prop 计算总页数，若首次加载时未设置或设置了错误的值，分页计算会出错。

**解决：** 在获取第一页数据的同时从接口返回 `total` 并赋值给 `totalRecords`，确保与数据同步更新。

```vue
<DataTable :value="rows" :lazy="true" :totalRecords="total" @page="onPage">

```

---

## 参见

- [Vue3入门](https://blog.vercanti.com/vue-3-ru-men-zhi-nan/)
- [Pinia完全指南](https://blog.vercanti.com/pinia-wan-quan-zhi-nan/)
- [TailwindCSS完全指南](https://blog.vercanti.com/tailwindcss-wan-quan-zhi-nan/)
- [Nuxt3完全指南](https://blog.vercanti.com/nuxt-3-wan-quan-zhi-nan/)