Appearance
主題設置
自訂主題
主題挑色
Configuration
js
// myCustomLightTheme.js
// 自訂的主題以內建的 light theme 參數為例
export default {
dark: false,
colors: {
background: '#FFFFFF',
surface: '#FFFFFF',
'surface-variant': '#424242',
'on-surface-variant': '#EEEEEE',
primary: '#6200EE',
'primary-darken-1': '#3700B3',
secondary: '#03DAC6',
'secondary-darken-1': '#018786',
error: '#B00020',
info: '#2196F3',
success: '#4CAF50',
warning: '#FB8C00',
},
variables: {
'border-color': '#000000',
'border-opacity': 0.12,
'high-emphasis-opacity': 0.87,
'medium-emphasis-opacity': 0.60,
'disabled-opacity': 0.38,
'idle-opacity': 0.04,
'hover-opacity': 0.04,
'focus-opacity': 0.12,
'selected-opacity': 0.08,
'activated-opacity': 0.12,
'pressed-opacity': 0.12,
'dragged-opacity': 0.08,
'theme-kbd': '#212529',
'theme-on-kbd': '#FFFFFF',
'theme-code': '#F5F5F5',
'theme-on-code': '#000000',
},
}
// myCustomLightTheme.js
// 自訂的主題以內建的 light theme 參數為例
export default {
dark: false,
colors: {
background: '#FFFFFF',
surface: '#FFFFFF',
'surface-variant': '#424242',
'on-surface-variant': '#EEEEEE',
primary: '#6200EE',
'primary-darken-1': '#3700B3',
secondary: '#03DAC6',
'secondary-darken-1': '#018786',
error: '#B00020',
info: '#2196F3',
success: '#4CAF50',
warning: '#FB8C00',
},
variables: {
'border-color': '#000000',
'border-opacity': 0.12,
'high-emphasis-opacity': 0.87,
'medium-emphasis-opacity': 0.60,
'disabled-opacity': 0.38,
'idle-opacity': 0.04,
'hover-opacity': 0.04,
'focus-opacity': 0.12,
'selected-opacity': 0.08,
'activated-opacity': 0.12,
'pressed-opacity': 0.12,
'dragged-opacity': 0.08,
'theme-kbd': '#212529',
'theme-on-kbd': '#FFFFFF',
'theme-code': '#F5F5F5',
'theme-on-code': '#000000',
},
}
js
// src/plugins/vuetify.js
import '@mdi/font/css/materialdesignicons.css'
import 'vuetify/styles'
// Composables
import { createVuetify } from 'vuetify'
import myCustomLightTheme from 'myCustomLightTheme.js'
// https://vuetifyjs.com/en/introduction/why-vuetify/#feature-guides
export default createVuetify({
theme: {
// 設置app預設主題,除了可用的主題選項還有 vuetify 內建的 light/dark
defaultTheme: 'myCustomLightTheme',
// 讓 vuetify 自動建立 color variantions
// 例如這個設定會有:text-primary-lighten-1, text-primary-darken-1, text-primary-darken-2
variations: {
colors: ['primary', 'secondary'],
lighten: 1,
darken: 2,
},
// 可用的主題選項
themes: {
myCustomLightTheme,
}
}
})
// src/plugins/vuetify.js
import '@mdi/font/css/materialdesignicons.css'
import 'vuetify/styles'
// Composables
import { createVuetify } from 'vuetify'
import myCustomLightTheme from 'myCustomLightTheme.js'
// https://vuetifyjs.com/en/introduction/why-vuetify/#feature-guides
export default createVuetify({
theme: {
// 設置app預設主題,除了可用的主題選項還有 vuetify 內建的 light/dark
defaultTheme: 'myCustomLightTheme',
// 讓 vuetify 自動建立 color variantions
// 例如這個設定會有:text-primary-lighten-1, text-primary-darken-1, text-primary-darken-2
variations: {
colors: ['primary', 'secondary'],
lighten: 1,
darken: 2,
},
// 可用的主題選項
themes: {
myCustomLightTheme,
}
}
})
動態切換主題
vue
<template>
<v-app>
<v-btn @click="toggleTheme">主題切換</v-btn>
</v-app>
</template>
<script setup>
import { useTheme } from 'vuetify'
// 用 useTheme 取得 theme 實體(A.K.A. 一個 javascript 物件)。
const theme = useTheme();
// 透過改變 theme.global.name 的值切換主題。
const toggleTheme = () => theme.global.name.value = theme.global.current.value.dark ? 'light' : 'dark'
// 可能有人不習慣官方的寫法,以下用等價的程式解釋程式
// P.S. 所謂等價程式,是指不考慮兩種寫法當中的 hoisting/TDZ(提升/暫時性死區)、this binding(this 指涉) 等等細節差異。
/*
function toggleTheme(){
const isDark = theme.global.current.value.dark;
const theme = isDark ? 'light' : 'dark';
theme.global.name.value = theme;
}
*/
</script>
<template>
<v-app>
<v-btn @click="toggleTheme">主題切換</v-btn>
</v-app>
</template>
<script setup>
import { useTheme } from 'vuetify'
// 用 useTheme 取得 theme 實體(A.K.A. 一個 javascript 物件)。
const theme = useTheme();
// 透過改變 theme.global.name 的值切換主題。
const toggleTheme = () => theme.global.name.value = theme.global.current.value.dark ? 'light' : 'dark'
// 可能有人不習慣官方的寫法,以下用等價的程式解釋程式
// P.S. 所謂等價程式,是指不考慮兩種寫法當中的 hoisting/TDZ(提升/暫時性死區)、this binding(this 指涉) 等等細節差異。
/*
function toggleTheme(){
const isDark = theme.global.current.value.dark;
const theme = isDark ? 'light' : 'dark';
theme.global.name.value = theme;
}
*/
</script>
使用不同主題
使用 theme="dark"
直接把指定組件的 theme props,會影響該下游組件的主題
vue
<template>
<v-app>
<v-card theme="dark">
<!-- button uses dark theme -->
<v-btn>foo</v-btn>
</v-card>
</v-app>
</template>
<template>
<v-app>
<v-card theme="dark">
<!-- button uses dark theme -->
<v-btn>foo</v-btn>
</v-card>
</v-app>
</template>
使用 <v-theme-provider>
使用 <v-theme-provider>
圈選要套用主題的區域
vue
<template>
<v-app>
<!-- uses the current default theme -->
<v-card>...</v-card>
<v-theme-provider theme="high-contrast">
<!-- uses the high-contrast theme -->
<v-card>...</v-card>
<v-btn>...</v-btn>
</v-theme-provider>
</v-app>
</template>
<template>
<v-app>
<!-- uses the current default theme -->
<v-card>...</v-card>
<v-theme-provider theme="high-contrast">
<!-- uses the high-contrast theme -->
<v-card>...</v-card>
<v-btn>...</v-btn>
</v-theme-provider>
</v-app>
</template>
vuetify3/vuetify2 (較重要)差異:
- 雙主題(light/dark)改為多主題(Multiple themes):捨棄元件的 light/dark props,改用類似
theme="dark"
的方式指定元件主題,一旦元件透過theme="dark"
指定主題,下游元件會自動獲得該主題。 - variant class 和 theme 結合:
class="primary darken-1"
改為class="primary-darken-1"
Reference
- Vuetify-Features-Theme configuration
- Vuetify-Style and animations-Material color palette
- MATERIAL DESIGN 2
- MATERIAL DESIGN 3
- mui theme creator
- [GitHub]vuetifyjs/vuetify-theme.ts
https://m3.material.io/theme-builder#/custom 切換主題的方法
https://stackoverflow.com/questions/62005958/vuetify-toggle-between-light-and-dark-theme-with-vuex