从各种预设主题中选择,或者开发自己的主题。
PrimeVue 是一个与设计无关的库,因此与其他一些 UI 库不同,它不会强制执行特定的样式,例如材料设计。样式使用主题与组件分离。主题包含两个部分:*基础* 和 *预设*。基础是使用 CSS 变量作为占位符的样式规则,而预设是一组设计令牌,用于通过将令牌映射到 CSS 变量来馈送基础。基础可以配置不同的预设,目前,光环、拉拉和诺拉是可用的预设,在即将推出的版本中将提供更多预设,例如 Material Design。
样式模式架构的核心是基于名为 *设计令牌* 的概念,预设在 3 个层级定义令牌配置:*原始*、*语义* 和 *组件*。
原始令牌没有上下文,颜色调色板是原始令牌的一个很好的例子,例如 *blue-50* 到 *blue-900*。名为 *blue-500* 的令牌可以用作主要颜色,消息的背景,但就其本身而言,令牌的名称不会指示上下文。通常,它们由语义令牌使用。
语义令牌定义内容,它们的名称指示它们的使用位置,*primary.color* 是语义令牌的一个众所周知的例子。语义令牌映射到原始令牌或其他语义令牌。*colorScheme* 令牌组是一个特殊的变量,用于根据应用程序中激活的颜色方案定义令牌,这允许根据颜色方案(如深色模式)定义不同的令牌。
组件令牌是每个组件的独立令牌,例如 *inputtext.background* 或 *button.color*,它们映射到语义令牌。例如,*button.background* 组件令牌映射到 *primary.color* 语义令牌,该令牌映射到 *green.500* 原始令牌。
在定义核心调色板时使用原始令牌,并使用语义令牌指定通用设计元素,例如焦点环、主要颜色和表面。组件令牌仅应在自定义特定组件时使用。通过将您自己的设计令牌定义为自定义预设,您将能够定义自己的样式,而无需接触 CSS。使用样式类覆盖 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 层 内定义(默认情况下名为 *primeui*)或不定义。CSS 层将有助于声明自定义级联层,以便于自定义。默认值为 *false*。
options: {
cssLayer: {
name: 'primevue',
order: 'tailwind-base, primevue, tailwind-utilities'
}
}
目前,光环、拉拉和诺拉是可用的预设,一个基于 Material Design 的新预设计划于 2024 年底发布。
import accordion from '@primevue/themes/aura/accordion';
// ... imports of other component tokens
export default {
primitive: {
borderRadius: {
none: '0',
xs: '2px',
sm: '4px',
md: '6px',
lg: '8px',
xl: '12px'
},
emerald: { 50: '#ecfdf5', 100: '#d1fae5', 200: '#a7f3d0', 300: '#6ee7b7', 400: '#34d399', 500: '#10b981', 600: '#059669', 700: '#047857', 800: '#065f46', 900: '#064e3b', 950: '#022c22' },
green: { 50: '#f0fdf4', 100: '#dcfce7', 200: '#bbf7d0', 300: '#86efac', 400: '#4ade80', 500: '#22c55e', 600: '#16a34a', 700: '#15803d', 800: '#166534', 900: '#14532d', 950: '#052e16' },
lime: { 50: '#f7fee7', 100: '#ecfccb', 200: '#d9f99d', 300: '#bef264', 400: '#a3e635', 500: '#84cc16', 600: '#65a30d', 700: '#4d7c0f', 800: '#3f6212', 900: '#365314', 950: '#1a2e05' },
red: { 50: '#fef2f2', 100: '#fee2e2', 200: '#fecaca', 300: '#fca5a5', 400: '#f87171', 500: '#ef4444', 600: '#dc2626', 700: '#b91c1c', 800: '#991b1b', 900: '#7f1d1d', 950: '#450a0a' },
orange: { 50: '#fff7ed', 100: '#ffedd5', 200: '#fed7aa', 300: '#fdba74', 400: '#fb923c', 500: '#f97316', 600: '#ea580c', 700: '#c2410c', 800: '#9a3412', 900: '#7c2d12', 950: '#431407' },
amber: { 50: '#fffbeb', 100: '#fef3c7', 200: '#fde68a', 300: '#fcd34d', 400: '#fbbf24', 500: '#f59e0b', 600: '#d97706', 700: '#b45309', 800: '#92400e', 900: '#78350f', 950: '#451a03' },
yellow: { 50: '#fefce8', 100: '#fef9c3', 200: '#fef08a', 300: '#fde047', 400: '#facc15', 500: '#eab308', 600: '#ca8a04', 700: '#a16207', 800: '#854d0e', 900: '#713f12', 950: '#422006' },
teal: { 50: '#f0fdfa', 100: '#ccfbf1', 200: '#99f6e4', 300: '#5eead4', 400: '#2dd4bf', 500: '#14b8a6', 600: '#0d9488', 700: '#0f766e', 800: '#115e59', 900: '#134e4a', 950: '#042f2e' },
cyan: { 50: '#ecfeff', 100: '#cffafe', 200: '#a5f3fc', 300: '#67e8f9', 400: '#22d3ee', 500: '#06b6d4', 600: '#0891b2', 700: '#0e7490', 800: '#155e75', 900: '#164e63', 950: '#083344' },
sky: { 50: '#f0f9ff', 100: '#e0f2fe', 200: '#bae6fd', 300: '#7dd3fc', 400: '#38bdf8', 500: '#0ea5e9', 600: '#0284c7', 700: '#0369a1', 800: '#075985', 900: '#0c4a6e', 950: '#082f49' },
blue: { 50: '#eff6ff', 100: '#dbeafe', 200: '#bfdbfe', 300: '#93c5fd', 400: '#60a5fa', 500: '#3b82f6', 600: '#2563eb', 700: '#1d4ed8', 800: '#1e40af', 900: '#1e3a8a', 950: '#172554' },
indigo: { 50: '#eef2ff', 100: '#e0e7ff', 200: '#c7d2fe', 300: '#a5b4fc', 400: '#818cf8', 500: '#6366f1', 600: '#4f46e5', 700: '#4338ca', 800: '#3730a3', 900: '#312e81', 950: '#1e1b4b' },
violet: { 50: '#f5f3ff', 100: '#ede9fe', 200: '#ddd6fe', 300: '#c4b5fd', 400: '#a78bfa', 500: '#8b5cf6', 600: '#7c3aed', 700: '#6d28d9', 800: '#5b21b6', 900: '#4c1d95', 950: '#2e1065' },
purple: { 50: '#faf5ff', 100: '#f3e8ff', 200: '#e9d5ff', 300: '#d8b4fe', 400: '#c084fc', 500: '#a855f7', 600: '#9333ea', 700: '#7e22ce', 800: '#6b21a8', 900: '#581c87', 950: '#3b0764' },
fuchsia: { 50: '#fdf4ff', 100: '#fae8ff', 200: '#f5d0fe', 300: '#f0abfc', 400: '#e879f9', 500: '#d946ef', 600: '#c026d3', 700: '#a21caf', 800: '#86198f', 900: '#701a75', 950: '#4a044e' },
pink: { 50: '#fdf2f8', 100: '#fce7f3', 200: '#fbcfe8', 300: '#f9a8d4', 400: '#f472b6', 500: '#ec4899', 600: '#db2777', 700: '#be185d', 800: '#9d174d', 900: '#831843', 950: '#500724' },
rose: { 50: '#fff1f2', 100: '#ffe4e6', 200: '#fecdd3', 300: '#fda4af', 400: '#fb7185', 500: '#f43f5e', 600: '#e11d48', 700: '#be123c', 800: '#9f1239', 900: '#881337', 950: '#4c0519' },
slate: { 50: '#f8fafc', 100: '#f1f5f9', 200: '#e2e8f0', 300: '#cbd5e1', 400: '#94a3b8', 500: '#64748b', 600: '#475569', 700: '#334155', 800: '#1e293b', 900: '#0f172a', 950: '#020617' },
gray: { 50: '#f9fafb', 100: '#f3f4f6', 200: '#e5e7eb', 300: '#d1d5db', 400: '#9ca3af', 500: '#6b7280', 600: '#4b5563', 700: '#374151', 800: '#1f2937', 900: '#111827', 950: '#030712' },
zinc: { 50: '#fafafa', 100: '#f4f4f5', 200: '#e4e4e7', 300: '#d4d4d8', 400: '#a1a1aa', 500: '#71717a', 600: '#52525b', 700: '#3f3f46', 800: '#27272a', 900: '#18181b', 950: '#09090b' },
neutral: { 50: '#fafafa', 100: '#f5f5f5', 200: '#e5e5e5', 300: '#d4d4d4', 400: '#a3a3a3', 500: '#737373', 600: '#525252', 700: '#404040', 800: '#262626', 900: '#171717', 950: '#0a0a0a' },
stone: { 50: '#fafaf9', 100: '#f5f5f4', 200: '#e7e5e4', 300: '#d6d3d1', 400: '#a8a29e', 500: '#78716c', 600: '#57534e', 700: '#44403c', 800: '#292524', 900: '#1c1917', 950: '#0c0a09' }
},
semantic: {
transitionDuration: '0.2s',
focusRing: {
width: '1px',
style: 'solid',
color: '{primary.color}',
offset: '2px',
shadow: 'none'
},
disabledOpacity: '0.6',
iconSize: '1rem',
anchorGutter: '2px',
primary: {
50: '{emerald.50}',
100: '{emerald.100}',
200: '{emerald.200}',
300: '{emerald.300}',
400: '{emerald.400}',
500: '{emerald.500}',
600: '{emerald.600}',
700: '{emerald.700}',
800: '{emerald.800}',
900: '{emerald.900}',
950: '{emerald.950}'
},
formField: {
paddingX: '0.75rem',
paddingY: '0.5rem',
borderRadius: '{border.radius.md}',
focusRing: {
width: '0',
style: 'none',
color: 'transparent',
offset: '0',
shadow: 'none'
},
transitionDuration: '{transition.duration}'
},
list: {
padding: '0.25rem 0.25rem',
gap: '2px',
header: {
padding: '0.5rem 0.75rem 0.25rem 0.75rem'
},
option: {
padding: '0.5rem 0.75rem',
borderRadius: '{border.radius.sm}'
},
optionGroup: {
padding: '0.5rem 0.75rem',
fontWeight: '600'
}
},
content: {
borderRadius: '{border.radius.md}'
},
mask: {
transitionDuration: '0.15s'
},
navigation: {
list: {
padding: '0.25rem 0.25rem',
gap: '2px'
},
item: {
padding: '0.5rem 0.75rem',
borderRadius: '{border.radius.sm}',
gap: '0.5rem'
},
submenuLabel: {
padding: '0.5rem 0.75rem',
fontWeight: '600'
},
submenuIcon: {
size: '0.875rem'
}
},
overlay: {
select: {
borderRadius: '{border.radius.md}',
shadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)'
},
popover: {
borderRadius: '{border.radius.md}',
padding: '0.75rem',
shadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)'
},
modal: {
borderRadius: '{border.radius.xl}',
padding: '1.25rem',
shadow: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)'
},
navigation: {
shadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)'
}
},
colorScheme: {
light: {
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}'
},
primary: {
color: '{primary.500}',
contrastColor: '#ffffff',
hoverColor: '{primary.600}',
activeColor: '{primary.700}'
},
highlight: {
background: '{primary.50}',
focusBackground: '{primary.100}',
color: '{primary.700}',
focusColor: '{primary.800}'
},
mask: {
background: 'rgba(0,0,0,0.4)',
color: '{surface.200}'
},
formField: {
background: '{surface.0}',
disabledBackground: '{surface.200}',
filledBackground: '{surface.50}',
filledFocusBackground: '{surface.50}',
borderColor: '{surface.300}',
hoverBorderColor: '{surface.400}',
focusBorderColor: '{primary.color}',
invalidBorderColor: '{red.400}',
color: '{surface.700}',
disabledColor: '{surface.500}',
placeholderColor: '{surface.500}',
floatLabelColor: '{surface.500}',
floatLabelFocusColor: '{surface.500}',
floatLabelInvalidColor: '{red.400}',
iconColor: '{surface.400}',
shadow: '0 0 #0000, 0 0 #0000, 0 1px 2px 0 rgba(18, 18, 23, 0.05)'
},
text: {
color: '{surface.700}',
hoverColor: '{surface.800}',
mutedColor: '{surface.500}',
hoverMutedColor: '{surface.600}'
},
content: {
background: '{surface.0}',
hoverBackground: '{surface.100}',
borderColor: '{surface.200}',
color: '{text.color}',
hoverColor: '{text.hover.color}'
},
overlay: {
select: {
background: '{surface.0}',
borderColor: '{surface.200}',
color: '{text.color}'
},
popover: {
background: '{surface.0}',
borderColor: '{surface.200}',
color: '{text.color}'
},
modal: {
background: '{surface.0}',
borderColor: '{surface.200}',
color: '{text.color}'
}
},
list: {
option: {
focusBackground: '{surface.100}',
selectedBackground: '{highlight.background}',
selectedFocusBackground: '{highlight.focus.background}',
color: '{text.color}',
focusColor: '{text.hover.color}',
selectedColor: '{highlight.color}',
selectedFocusColor: '{highlight.focus.color}',
icon: {
color: '{surface.400}',
focusColor: '{surface.500}'
}
},
optionGroup: {
background: 'transparent',
color: '{text.muted.color}'
}
},
navigation: {
item: {
focusBackground: '{surface.100}',
activeBackground: '{surface.100}',
color: '{text.color}',
focusColor: '{text.hover.color}',
activeColor: '{text.hover.color}',
icon: {
color: '{surface.400}',
focusColor: '{surface.500}',
activeColor: '{surface.500}'
}
},
submenuLabel: {
background: 'transparent',
color: '{text.muted.color}'
},
submenuIcon: {
color: '{surface.400}',
focusColor: '{surface.500}',
activeColor: '{surface.500}'
}
}
},
dark: {
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}'
},
primary: {
color: '{primary.400}',
contrastColor: '{surface.900}',
hoverColor: '{primary.300}',
activeColor: '{primary.200}'
},
highlight: {
background: 'color-mix(in srgb, {primary.400}, transparent 84%)',
focusBackground: 'color-mix(in srgb, {primary.400}, transparent 76%)',
color: 'rgba(255,255,255,.87)',
focusColor: 'rgba(255,255,255,.87)'
},
mask: {
background: 'rgba(0,0,0,0.6)',
color: '{surface.200}'
},
formField: {
background: '{surface.950}',
disabledBackground: '{surface.700}',
filledBackground: '{surface.800}',
filledFocusBackground: '{surface.800}',
borderColor: '{surface.700}',
hoverBorderColor: '{surface.600}',
focusBorderColor: '{primary.color}',
invalidBorderColor: '{red.300}',
color: '{surface.0}',
disabledColor: '{surface.400}',
placeholderColor: '{surface.400}',
floatLabelColor: '{surface.400}',
floatLabelFocusColor: '{surface.400}',
floatLabelInvalidColor: '{red.300}',
iconColor: '{surface.400}',
shadow: '0 0 #0000, 0 0 #0000, 0 1px 2px 0 rgba(18, 18, 23, 0.05)'
},
text: {
color: '{surface.0}',
hoverColor: '{surface.0}',
mutedColor: '{surface.400}',
hoverMutedColor: '{surface.300}'
},
content: {
background: '{surface.900}',
hoverBackground: '{surface.800}',
borderColor: '{surface.700}',
color: '{text.color}',
hoverColor: '{text.hover.color}'
},
overlay: {
select: {
background: '{surface.900}',
borderColor: '{surface.700}',
color: '{text.color}'
},
popover: {
background: '{surface.900}',
borderColor: '{surface.700}',
color: '{text.color}'
},
modal: {
background: '{surface.900}',
borderColor: '{surface.700}',
color: '{text.color}'
}
},
list: {
option: {
focusBackground: '{surface.800}',
selectedBackground: '{highlight.background}',
selectedFocusBackground: '{highlight.focus.background}',
color: '{text.color}',
focusColor: '{text.hover.color}',
selectedColor: '{highlight.color}',
selectedFocusColor: '{highlight.focus.color}',
icon: {
color: '{surface.500}',
focusColor: '{surface.400}'
}
},
optionGroup: {
background: 'transparent',
color: '{text.muted.color}'
}
},
navigation: {
item: {
focusBackground: '{surface.800}',
activeBackground: '{surface.800}',
color: '{text.color}',
focusColor: '{text.hover.color}',
activeColor: '{text.hover.color}',
icon: {
color: '{surface.500}',
focusColor: '{surface.400}',
activeColor: '{surface.400}'
}
},
submenuLabel: {
background: 'transparent',
color: '{text.muted.color}'
},
submenuIcon: {
color: '{surface.500}',
focusColor: '{surface.400}',
activeColor: '{surface.400}'
}
}
}
}
},
components: {
accordion,
// ... other components
}
};
令牌使用点分隔符描述,例如 *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*。
*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}'
}
}
});
*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)'
}
}
}
}
});
颜色方案调色板在亮模式和暗模式之间变化,使用表面令牌指定。以下示例使用 *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}'
}
}
}
}
});
没有字体设计,因为 UI 组件继承其字体设置来自应用程序。
表单输入组件的设计令牌源自 *form.field* 令牌组。此自定义示例将悬停时的边框颜色更改为主要颜色。任何依赖此语义令牌的组件,例如 *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}'
}
}
}
}
}
});
设计令牌可以使用 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}');
预设的调色板由 *primitive* 设计令牌组定义。默认颜色源自 Tailwind 颜色,并有一些扩展,使其与无样式模式的 Tailwind Presets 项目保持一致。
颜色可以在 CSS 中作为变量访问,也可以使用 *dt* 实用程序以编程方式访问。
// With CSS
var(--p-blue-500)
// With JS
$dt('blue.500').value
PrimeVue 在主题配置中使用系统作为默认的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() {
const element = document.querySelector('html');
element.classList.toggle('my-app-dark');
}
如果您希望始终使用暗黑模式,请首先应用darkModeSelector,并且不要更改它。
PrimeVue CSS 层仅在主题配置中显式启用分层时才应用于样式化模式。在非样式化模式下,内置的 CSS 类不包括在内,因此不需要任何层。
@layer 是一个标准的 CSS 功能,用于定义自定义优先级顺序的级联层。如果您需要更熟悉层,请访问 MDN 文档以开始学习。在样式化模式下,当在主题配置中启用cssLayer 选项时,PrimeVue 会将内置的样式类包装在primevue 级联层下,使库样式易于覆盖。您应用程序中的 CSS 没有任何层,具有最高的 CSS 特异性,因此您将能够覆盖样式,无论位置或类名如何强。
例如,假设您需要删除正在使用的主题中定义的 ToggleSwitch 组件的圆角边框。为了实现这一点,需要覆盖.p-toggleswitch .p-toggleswitch-slider 选择器。如果没有层,我们将不得不编写更强的 CSS 或使用!important,但是,使用层,这不会出现问题,因为您的 CSS 可以始终通过更简单的类名(例如my-switch-slider)覆盖 PrimeVue。这种方法的另一个优点是,它不会强迫您找出组件的内置类名。
<template>
<ToggleSwitch v-model="checked" :pt="{ slider: 'my-switch-slider' }" />
</template>
<script>
import { ref } from "vue";
const checked = ref(false);
</script>
<style>
.my-switch-slider {
border-radius: 0;
}
.my-switch-slider:before {
border-radius: 0;
}
</style>
层也使使用 CSS 模块变得更容易,查看 CSS 模块指南以获取示例。
如果您在 HTML 元素(如输入和按钮)上具有全局样式,而这些样式也被 PrimeVue 使用,则自定义的简便性可能会出现问题,因为范围更广的全局样式(例如button { } 且没有层)始终会覆盖 PrimeVue 组件,导致意外的结果。全局样式应用于标准 HTML 元素的一个常见用例是 CSS 重置实用程序,用于删除浏览器的默认样式。在这种情况下,最佳实践是在层中包装您的 CSS,例如reset,并确保primevue 在您的层之后,因为之后定义的层具有更高的优先级。这样,您的重置 CSS 不会妨碍 PrimeVue 组件。
/* Order */
@layer reset, primevue;
/* Reset CSS */
@layer reset {
button,
input {
/* CSS to Reset */
}
}
流行 CSS 库的示例层配置。
Bootstrap 有一个reboot 实用程序来重置标准元素的 CSS。如果您包含此实用程序,您可以在导入时为其提供一个层。
@layer bootstrap-reboot, primevue;
@import "bootstrap-reboot.css" layer(bootstrap-rebooot);
Tailwind CSS 在 base 中包含一个重置实用程序,称为 preflight。如果您使用此功能,请将 base 和实用程序包装在单独的层中,并确保 primevue 层位于 base 之后。
@layer tailwind-base, primevue, tailwind-utilities;
@layer tailwind-base {
@tailwind base;
}
@layer tailwind-utilities {
@tailwind components;
@tailwind utilities;
}
Normalize 是另一个用于重置标准元素 CSS 的实用程序。在导入 CSS 文件时,将其分配给一个层,并使用 primevue 在归一化层之后定义层顺序。
@layer normalize, primevue;
@import "normalize.css" layer(normalize-reset);
CSS 模块 通过在您的 SFC 中的样式元素上启用module 属性来支持。使用$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;
}