传递属性是一种用于访问组件内部 DOM 结构的 API。
在传统的第三方 UI 库中,用户仅限于组件作者提供的 API。此 API 通常包括 props、事件和插槽。每当需要 API 中的新自定义选项时,组件作者都需要开发并通过新版本发布。
PrimeTek 的愿景是您的组件,而不是我们的。传递属性功能是通过暴露组件内部结构以将任意属性和侦听器应用于 DOM 元素来实现此愿景的关键要素。这种方法的主要优点是让您不再受主组件 API 的限制。我们建议您在需要定制组件但缺少针对您的特定需求的内置功能时考虑使用传递属性功能。
PrimeTV YouTube 频道提供了两个视频,第一个是介绍,第二个涵盖了通过传递属性解决的独特案例。
每个组件都有一个特殊的 pt 属性,用于定义一个对象,其键对应于可用的 DOM 元素。每个值可以是字符串、对象或返回字符串或对象的函数,用于定义要应用于元素的任意属性,例如样式、aria、data-* 或自定义属性。如果值是字符串或返回字符串的函数,则将其视为类定义并添加到元素的 class 属性中。每个组件文档都有一个专门的部分来记录通过 PT 公开的可用部分名称。
pt 最常见的用法是样式和自定义。class 和 style 属性支持相应的 Vue 绑定 的确切语法,例如数组、对象和条件。下面的示例使用 PrimeFlex CSS 库设置 Panel 组件的样式。
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
<Panel header="Header" toggleable
:pt="{
header: (options) => ({
id: 'myPanelHeader',
style: {
'user-select': 'none'
},
class: [
'border-primary',
{
'bg-primary text-primary-contrast': options.state.d_collapsed,
'text-primary bg-primary-contrast': !options.state.d_collapsed
}
]
}),
content: { class: 'border-primary text-lg text-primary-700' },
title: 'text-xl', // OR { class: 'text-xl' }
toggler: () => 'bg-primary text-primary-contrast hover:text-primary hover:bg-primary-contrast' // OR { class: 'bg-primary text-primary-contrast hover:text-primary hover:bg-primary-contrast' }
}">
<p class="m-0">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
</Panel>
声明式语法提供了程序式语法的替代方案。以 pt 开头的属性由组件根据以下格式进行不同的解释。此外,正在计划 IDE 扩展,以自动完成值,从而在将来获得更好的开发人员体验。
<ComponentTag pt:[passthrough_key]:[attribute]="value" />
这是另一个示例,使用相同的选项的两种语法替代方案。
<Panel
:pt="{
root: {
class='"border-1 border-solid'
},
header: {
'data-test-id': 'testid',
class: 'bg-blue-500',
onClick: onHeaderClick
}
}"
>
<Panel
pt:root:class="border border-solid"
pt:header:id="headerId"
pt:header:data-test-id="testId"
pt:header:class="bg-blue-500"
:pt:header:onClick="onHeaderClick"
>
以 pc 为前缀的部分名称表示 PrimeVue 组件,将其与标准 DOM 元素区分开来,并指示需要嵌套结构。例如,“badge” 部分被标识为 pcBadge,因为按钮组件在内部集成了 badge 组件。
<Button
type="button"
label="Messages"
icon="pi pi-inbox"
badge="2"
variant="outlined"
severity="secondary"
:pt="{
root: '!px-4 !py-3',
icon: '!text-xl !text-violet-500 dark:!text-violet-400',
label: '!text-lg !text-violet-500 dark:!text-violet-400',
pcBadge: {
root: '!bg-violet-500 dark:!bg-violet-400 !text-white dark:!text-black'
}
}"
/>
组件的生命周期钩子通过 hooks 属性作为传递属性公开,以便可以注册回调函数。可用的回调是 onBeforeCreate、onCreated、onBeforeUpdate、onUpdated、onBeforeMount、onMounted、onBeforeUnmount 和 onUnmounted。有关生命周期钩子的详细信息,请参阅 Vue.js 文档。
<Panel header="Header" :pt="panelPT">
Content
</Panel>
定义每个组件类型的共享传递属性。例如,在以下配置中,所有面板标题都具有 bg-primary 样式类,并且所有自动完成组件都具有固定宽度。这些设置可以被特定组件覆盖,因为组件的 pt 属性的优先级高于全局 pt。
import { createApp } from "vue";
import PrimeVue from "primevue/config";
const app = createApp(App);
app.use(PrimeVue, {
pt: {
panel: {
header: {
class: 'bg-primary text-primary-contrast'
}
},
autocomplete: {
input: {
root: 'w-64' // OR { class: 'w-64' }
}
}
}
});
global 属性具有一个 css 选项,用于定义属于全局 pt 配置的自定义 css。此功能的常见用例是定义与传递属性配置相关的全局样式和动画。
import { createApp } from "vue";
import PrimeVue from "primevue/config";
const app = createApp(App);
app.use(PrimeVue, {
pt: {
global: {
css: `
.my-button {
border-width: 2px;
}
`
},
button: {
root: 'my-button'
}
}
});
使用 usePassThrough 实用程序自定义现有的传递属性配置。第一个参数是要自定义的对象,第二个参数是自定义项,最后一个参数是合并策略。
import { createApp } from "vue";
import PrimeVue from "primevue/config";
import { usePassThrough } from "primevue/passthrough";
import BasePreset from "./basepreset";
const app = createApp(App);
const CustomPreset = usePassThrough(
BasePreset,
{
panel: {
title: {
class: ['leading-none font-light text-2xl']
}
}
},
{
mergeSections: true,
mergeProps: false
}
);
app.use(PrimeVue, { unstyled: true, pt: CustomPreset });
mergeSections 定义是否添加主配置中的部分,mergeProps 控制是覆盖还是合并定义的 props。mergeSections 的默认值为 true,mergeProps 的默认值为 false。
const CustomPreset = usePassThrough(
BasePreset,
{
panel: {
header: 'my_panel_header'
}
},
{ mergeSections: true, mergeProps: false }
);
// Output:
// panel.header.class => 'my_panel_header'
// panel.title.class => Tailwind.panel.title.class
const CustomPreset = usePassThrough(
BasePreset,
{
panel: {
header: 'my_panel_header'
}
},
{ mergeSections: true, mergeProps: true }
);
// Output:
// panel.header.class => [Tailwind.panel.header.class, 'my_panel_header']
// panel.title.class => Tailwind.panel.title.class
const CustomPreset = usePassThrough(
BasePreset,
{
panel: {
header: 'my_panel_header'
}
},
{ mergeSections: false, mergeProps: true }
);
// Output:
// panel.header.class => [Tailwind.panel.header.class, 'my_panel_header']
// panel.title.class => undefined
const CustomPreset = usePassThrough(
BasePreset,
{
panel: {
header: 'my_panel_header'
}
},
{ mergeSections: false, mergeProps: false }
);
// Output:
// panel.header.class => 'my_panel_header'
// panel.title.class => undefined