透传

透传属性是一个 API,用于访问组件的内部 DOM 结构。

在传统的第三方 UI 库中,用户受限于组件作者提供的 API。此 API 通常包含 props、事件和插槽。每当出现对 API 中新的自定义选项的需求时,组件作者需要开发并在新版本中发布它。

PrimeTek 的愿景是您的组件,而不是我们的。透传功能是通过暴露组件内部结构,以便将任意属性和侦听器应用于 DOM 元素来实现此愿景的关键要素。此方法的主要优点在于,它使您不再受限于主组件 API。我们建议在需要定制缺少内置功能的组件以满足您的特定需求时,考虑使用透传功能。

PrimeTV youtube 频道提供了两个视频,第一个视频是介绍,第二个视频涵盖了透传解决的独特案例。

每个组件都有一个特殊的pt属性,用于定义一个对象,该对象的键对应于可用的 DOM 元素。每个值可以是字符串、对象或返回字符串或对象的函数,以定义要应用于元素的任意属性,例如样式、aria、data-* 或自定义属性。如果值是字符串或返回字符串的函数,则将其视为类定义并添加到元素的 class 属性中。每个组件文档都有一个专门的部分来记录通过 PT 公开的可用节名称。

pt最常见的用法是样式和自定义。classstyle属性支持相应的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 元素区分开来,并指示需要嵌套结构。例如,“徽章”节被标识为pcBadge,因为按钮组件在内部包含了徽章组件。


 <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属性作为透传公开,以便可以注册回调函数。可用的回调是onBeforeCreateonCreatedonBeforeUpdateonUpdatedonBeforeMountonMountedonBeforeUnmountonUnmounted。有关生命周期钩子的详细信息,请参阅 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的默认值为truemergeProps的默认值为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