从各种预设样式主题中选择,或开发您自己的主题。
PrimeVue 是一个与设计无关的库,因此与某些其他 UI 库不同,它不会强制使用某种样式,例如 Material Design。样式使用主题与组件解耦。主题由两部分组成:基础和预设。基础是带有 CSS 变量作为占位符的样式规则,而预设是一组设计令牌,通过将令牌映射到 CSS 变量来为基础提供数据。基础可以使用不同的预设进行配置,目前光环、材质、劳拉和诺拉是可用的内置选项。
样式模式架构的核心基于一个名为设计令牌的概念,预设在 3 个层级中定义令牌配置;原始、语义和组件。
原始令牌没有上下文,颜色调色板是原始令牌的一个很好的例子,例如蓝色-50到蓝色-900。名为蓝色-500的令牌可以用作主色、消息的背景,但在其自身上,令牌的名称并不指示上下文。通常它们被语义令牌利用。
语义令牌定义内容,它们的名称指示它们的使用位置,语义令牌的一个众所周知的例子是primary.color。语义令牌映射到原始令牌或其他语义令牌。colorScheme令牌组是一个特殊变量,用于定义基于应用程序中活动配色方案的令牌,这允许基于深色模式等配色方案定义不同的令牌。
组件令牌是每个组件的隔离令牌,例如映射到语义令牌的inputtext.background或button.color。例如,button.background组件令牌映射到primary.color语义令牌,后者映射到green.500原始令牌。
定义核心调色板时使用原始令牌,并使用语义令牌指定常见的元素设计,例如焦点环、主色和表面。组件令牌仅应在自定义特定组件时使用。通过将您自己的设计令牌定义为自定义预设,您将能够定义自己的样式,而无需修改 CSS。使用样式类覆盖 PrimeVue 组件不是最佳实践,应该作为最后的手段,建议使用设计令牌方法。
观看PrimeVue 主题揭秘系列,通过示例了解更多关于架构的信息。
theme 属性用于自定义初始主题。
import PrimeVue from 'primevue/config';
import Aura from '@primevue/themes/aura';
const app = createApp(App);
app.use(PrimeVue, {
// Default theme configuration
theme: {
preset: Aura,
options: {
prefix: 'p',
darkModeSelector: 'system',
cssLayer: false
}
}
});
options 属性定义如何从预设的设计令牌生成 CSS。
CSS 变量的前缀,默认为 p。例如,primary.color 设计令牌将为 var(--p-primary-color)。
options: {
prefix: 'my'
}
封装深色模式 CSS 变量的 CSS 规则,默认值为 system 以生成 @media (prefers-color-scheme: dark)。如果您需要根据用户选择使深色模式可切换,请定义一个类选择器,例如 .app-dark 并在文档根目录中切换此类。有关示例,请参阅深色模式切换部分。
options: {
darkModeSelector: '.my-app-dark'
}
定义样式是否应默认定义在 CSS 层 中。如果需要,CSS 层可以方便地声明自定义级联层以方便自定义。默认值为 false。
options: {
cssLayer: {
name: 'primevue',
order: 'app-styles, primevue, another-css-library'
}
}
光环、材质、劳拉和诺拉是可用的内置选项,旨在演示与设计无关的主题化的强大功能。光环是 PrimeTek 自己的愿景,材质遵循 Google Material Design v2,劳拉基于 Bootstrap,诺拉的灵感来自企业应用程序。访问源代码以了解有关预设结构的更多信息。您可以直接使用它们进行修改,或者在需要从头开始构建自己的预设时将它们用作参考。
令牌用点分隔符描述,例如primary.color、form.field.background 或 checkbox.icon.checked.color。在预设配置中,映射点分隔符时使用驼峰式大小写和对象属性。以下是复选框组件令牌的示例,用于表示 checkbox.icon.checked.color,所有替代方案都具有相同的结果。
export default {
iconCheckedColor: //...,
}
export default {
icon: {
checkedColor: //...
}
}
export default {
icon: {
checked: {
color: //...
}
}
}
以下键在预设方案中保留,不能用作令牌名称;primitive、semantic、components、directives、colorscheme、light、dark、common、root、states 和 extend。
预设的调色板由 primitive 设计令牌组定义。您可以使用 CSS 变量或 $dt 实用程序访问颜色。
// With CSS
var(--p-blue-500)
// With JS
$dt('blue.500').value
PrimeVue 使用 system 作为主题配置中的默认 darkModeSelector。如果您的应用程序中有深色模式切换,请将 darkModeSelector 设置为您使用的选择器,例如 .my-app-dark,以便 PrimeVue 可以无缝适应您的配色方案。
import PrimeVue from 'primevue/config';
import Aura from '@primevue/themes/aura';
const app = createApp(App);
app.use(PrimeVue, {
// Default theme configuration
theme: {
preset: Aura,
options: {
darkModeSelector: '.my-app-dark',
}
}
});
以下是深色模式切换的一个非常基本的示例实现,您可以通过涉及 prefers-color-scheme 从系统初始检索它并使用 localStorage 使其有状态来进一步扩展它。有关更多信息,请参阅这篇文章。
<Button label="Toggle Dark Mode" @click="toggleDarkMode()" />
function toggleDarkMode() {
document.documentElement.classList.toggle('my-app-dark');
}
如果您希望始终使用深色模式,请最初应用 darkModeSelector,并且永远不要更改它。
<html class="my-app-dark">
也可以使用 false 或 none 作为选择器的值来完全禁用深色模式。
theme: {
preset: Aura,
options: {
darkModeSelector: false || 'none',
}
}
definePreset 实用程序用于在 PrimeVue 设置期间自定义现有预设。第一个参数是要自定义的预设,第二个参数是要覆盖的设计令牌。
import PrimeVue from 'primevue/config';
import { definePreset } from '@primevue/themes';
import Aura from '@primevue/themes/aura';
const MyPreset = definePreset(Aura, {
//Your customizations, see the following sections for examples
});
app.use(PrimeVue, {
theme: {
preset: MyPreset
}
});
primary 定义了主色调,默认值映射到 emerald 原始令牌。我们将其设置为使用 indigo 代替。
const MyPreset = definePreset(Aura, {
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}'
}
}
});
在浅色和深色模式之间变化的配色方案调色板由表面令牌指定。下面的示例使用 zinc 用于浅色模式,slategray 用于深色模式。通过此设置,浅色模式将具有灰度色调,而深色模式将包含蓝色调。
const MyPreset = definePreset(Aura, {
semantic: {
colorScheme: {
light: {
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: {
surface: {
0: '#ffffff',
50: '{slate.50}',
100: '{slate.100}',
200: '{slate.200}',
300: '{slate.300}',
400: '{slate.400}',
500: '{slate.500}',
600: '{slate.600}',
700: '{slate.700}',
800: '{slate.800}',
900: '{slate.900}',
950: '{slate.950}'
}
}
}
}
});
noir 模式是使用表面色调作为主色的变体的昵称,需要额外的 colorScheme 配置来实现。一个以黑色和白色变体作为主色的示例预设配置:
const Noir = definePreset(Aura, {
semantic: {
primary: {
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}'
},
colorScheme: {
light: {
primary: {
color: '{zinc.950}',
inverseColor: '#ffffff',
hoverColor: '{zinc.900}',
activeColor: '{zinc.800}'
},
highlight: {
background: '{zinc.950}',
focusBackground: '{zinc.700}',
color: '#ffffff',
focusColor: '#ffffff'
}
},
dark: {
primary: {
color: '{zinc.50}',
inverseColor: '{zinc.950}',
hoverColor: '{zinc.100}',
activeColor: '{zinc.200}'
},
highlight: {
background: 'rgba(250, 250, 250, .16)',
focusBackground: 'rgba(250, 250, 250, .24)',
color: 'rgba(255,255,255,.87)',
focusColor: 'rgba(255,255,255,.87)'
}
}
}
}
});
没有针对字体的设计,因为 UI 组件会从应用程序继承其字体设置。
表单输入组件的设计令牌派生自 form.field 令牌组。此自定义示例将悬停时的边框颜色更改为 primary。任何依赖于此语义令牌的组件(例如 dropdown.hover.border.color 和 textarea.hover.border.color)都会收到更改。
const MyPreset = definePreset(Aura, {
semantic: {
colorScheme: {
light: {
formField: {
hoverBorderColor: '{primary.color}'
}
},
dark: {
formField: {
hoverBorderColor: '{primary.color}'
}
}
}
}
});
焦点环定义了轮廓宽度、样式、颜色和偏移量。让我们为轮廓使用更粗的环,并使用主色。
const MyPreset = definePreset(Aura, {
semantic: {
focusRing: {
width: '2px',
style: 'dashed',
color: '{primary.color}',
offset: '1px'
}
}
});
特定组件的设计令牌在 components 层定义。如果您正在构建自己的样式,不建议覆盖组件令牌,而应首选构建自己的预设。此配置是全局的,适用于所有卡片组件。如果您需要在页面上本地自定义特定组件,请查看“作用域 CSS”部分以获取示例。
const MyPreset = definePreset(Aura, {
components: {
card: {
colorScheme: {
light: {
root: {
background: '{surface.0}',
color: '{surface.700}'
},
subtitle: {
color: '{surface.500}'
}
},
dark: {
root: {
background: '{surface.900}',
color: '{surface.0}'
},
subtitle: {
color: '{surface.400}'
}
}
}
}
}
});
可以通过添加自定义设计令牌和附加样式来扩展主题系统。此功能提供了高度的自定义性,允许您根据需要调整样式,因为您不受默认令牌的限制。
示例预设配置添加了一个新的 accent 按钮,带有自定义的 button.accent.color 和 button.accent.inverse.color 令牌。也可以全局添加令牌,以便在组件中共享它们。
const MyPreset = definePreset(Aura, {
components: {
// custom button tokens and additional style
button: {
extend: {
accent: {
color: '#f59e0b',
inverseColor: '#ffffff'
}
}
css: ({ dt }) => `
.p-button-accent {
background: ${dt('button.accent.color')};
color: ${dt('button.accent.inverse.color')};
transition-duration: ${dt('my.transition.fast')};
}
`
}
},
// common tokens and styles
extend: {
my: {
transition: {
slow: '0.75s'
normal: '0.5s'
fast: '0.25s'
},
imageDisplay: 'block'
}
},
css: ({ dt }) => `
/* Global CSS */
img {
display: ${dt('my.image.display')};
}
`
});
可以使用 dt 属性将设计令牌作用域限定到某个组件。在此示例中,第一个开关使用全局令牌,而第二个开关使用自己的令牌覆盖全局令牌。
与 :deep() 相比,建议使用此方法,因为它提供了更简洁的 API,同时避免了 CSS 规则覆盖的麻烦。
<template>
<div>
<ToggleSwitch v-model="checked1" />
<ToggleSwitch v-model="checked2" :dt="amberSwitch" />
</div>
</template>
<script setup>
import { ref } from 'vue';
const checked1 = ref(true);
const checked2 = ref(true);
const amberSwitch = ref({
handle: {
borderRadius: '4px'
},
colorScheme: {
light: {
root: {
checkedBackground: '{amber.500}',
checkedHoverBackground: '{amber.600}',
borderRadius: '4px'
},
handle: {
checkedBackground: '{amber.50}',
checkedHoverBackground: '{amber.100}'
}
},
dark: {
root: {
checkedBackground: '{amber.400}',
checkedHoverBackground: '{amber.300}',
borderRadius: '4px'
},
handle: {
checkedBackground: '{amber.900}',
checkedHoverBackground: '{amber.800}'
}
}
}
});
</script>
完全替换当前的预设,常见的用例是在运行时动态更改预设。
import { usePreset } from '@primevue/themes';
const onButtonClick() {
usePreset(MyPreset);
}
将提供的令牌合并到当前预设,一个示例是动态更改主色调。
import { updatePreset } from '@primevue/themes';
const changePrimaryColor() {
updatePreset({
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}'
}
}
})
}
更新主色,这是使用 updatePreset 进行相同更新的简写。
import { updatePrimaryPalette } from '@primevue/themes';
const changePrimaryColor() {
updatePrimaryPalette({
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}'
});
}
更新表面色,这是使用 updatePreset 进行相同更新的简写。
import { updateSurfacePalette } from '@primevue/themes';
const changeSurfaces() {
//changes surfaces both in light and dark mode
updateSurfacePalette({
50: '{zinc.50}',
// ...
950: '{zinc.950}'
});
}
const changeLightSurfaces() {
//changes surfaces only in light
updateSurfacePalette({
light: {
50: '{zinc.50}',
// ...
950: '{zinc.950}'
}
});
}
const changeDarkSurfaces() {
//changes surfaces only in dark mode
updateSurfacePalette({
dark: {
50: '{zinc.50}',
// ...
950: '{zinc.950}'
}
});
}
$dt 函数返回有关令牌的信息,例如完整路径和值。如果您需要以编程方式访问令牌,这将非常有用。
import { $dt } from '@primevue/themes';
const duration = $dt('transition.duration');
/*
duration: {
name: '--transition-duration',
variable: 'var(--p-transition-duration)',
value: '0.2s'
}
*/
const primaryColor = $dt('primary.color');
/*
primaryColor: {
name: '--primary-color',
variable: 'var(--p-primary-color)',
value: {
light: {
value: '#10b981',
paths: {
name: 'semantic.primary.color',
binding: {
name: 'primitive.emerald.500'
}
}
},
dark: {
value: '#34d399',
paths: {
name: 'semantic.primary.color',
binding: {
name: 'primitive.emerald.400'
}
}
}
}
}
*/
以对象形式返回给定颜色从 50 到 950 的阴影和色调。
import { palette } from '@primevue/themes';
// custom color
const values1 = palette('#10b981');
// copy an existing token set
const primaryColor = palette('{blue}');
PrimeVue CSS 层仅在主题配置中显式启用分层时才应用于样式模式,在非样式模式下,不包括内置的 CSS 类,因此不需要任何层。
@layer 是一个标准的 CSS 功能,用于定义级联层,以便可以自定义优先级顺序。如果您需要更熟悉图层,请访问 MDN 上的文档以开始了解。
cssLayer 默认禁用,当在主题配置中启用它时,PrimeVue 会将内置样式类包装在 primevue 级联层下,以使库样式易于覆盖。您的应用程序中没有层的 CSS 具有最高的 CSS 特异性,因此无论位置或类的编写强度如何,您都可以覆盖样式。
图层还使 CSS 模块更容易使用,请查看 CSS 模块指南以获取示例。
如果 PrimeVue 组件在您的应用程序中存在视觉问题,则可能是 Reset CSS 造成的。CSS 层将是一个有效的解决方案,其中涉及启用 PrimeVue 层、将 Reset CSS 包装在另一层中并定义图层顺序。这样,您的 Reset CSS 就不会妨碍 PrimeVue 组件。
/* Order */
@layer reset, primevue;
/* Reset CSS */
@layer reset {
button,
input {
/* CSS to Reset */
}
}
通过在 SFC 中的样式元素上启用 module 属性来支持 CSS 模块。使用 $style 关键字将类应用于 PrimeVue 组件。建议在使用 CSS 模块时启用 cssLayer,以便 PrimeVue 样式具有较低的 CSS 特异性。
<style module>
.myinput {
border-radius: 2rem;
padding: 1rem 2rem;
border-width: 2px;
}
</style>
<template>
<InputText :class="$style.myinput" placeholder="Search" />
</template>
PrimeVue UI 组件使用 rem 单位,1rem 等于 html 元素的字体大小,默认值为 16px。使用根字体大小来全局调整组件的大小。此网站使用 14px 作为基本字体大小,因此如果您的基本字体大小不同,它可能与您的应用程序有所不同。
html {
font-size: 14px;
}