添加组件库 Element Plus
环境准备
拉取项目
# 从 GitHub 拉取项目(存在网络限制)
$ git clone --branch v0.0.4 https://github.com/geenln/vue3-elemnt-plus-ts.git
# 或者从 Gitee 拉取项目
$ git clone --branch v0.0.4 https://gitee.com/genin/vue3-elemnt-plus-ts.git
安装项目依赖
$ npm install
启动开发服务器
$ npm run dev
添加组件库 Element Plus
安装 Element Plus
$ npm install element-plus
更新文件 tsconfig.json 添加 Volar 支持
tsconfig.json
{
"compilerOptions": {
//...
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
},
+ "types": ["element-plus/global"]
},
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{"path": "./tsconfig.node.json"}]
}
添加按需导入、自动导入
$ npm install -D unplugin-vue-components unplugin-auto-import
更新文件 vite.config.ts 支持按需导入、自动导入
vite.config.ts
import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'
import {fileURLToPath} from 'node:url'
+import AutoImport from 'unplugin-auto-import/vite'
+import Components from 'unplugin-vue-components/vite'
+import {ElementPlusResolver} from 'unplugin-vue-components/resolvers'
// https://vitejs.dev/config/
export default defineConfig({
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
},
},
plugins: [
vue(),
+ AutoImport({
+ imports: ['vue', 'vue-router'],
+ resolvers: [ElementPlusResolver()],
+ eslintrc: {
+ enabled: true,
+ },
+ }),
+ Components({
+ resolvers: [ElementPlusResolver()],
+ }),
],
})
更新文件 eslint.config.js
eslint.config.js
import eslint from '@eslint/js'
import tseslint from 'typescript-eslint'
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'
import eslintConfigPrettier from 'eslint-config-prettier'
import eslintPluginVue from 'eslint-plugin-vue'
import vueEslintParser from 'vue-eslint-parser'
+import {readFile} from 'node:fs/promises'
+const eslintAutoImport = JSON.parse(
+ await readFile(
+ new URL('./.eslintrc-auto-import.json', import.meta.url),
+ 'utf8',
+ ),
+)
export default tseslint.config(
eslint.configs.recommended,
...eslintPluginVue.configs['flat/recommended'],
eslintPluginPrettierRecommended,
eslintConfigPrettier,
{ignores: ['dist/']},
{
languageOptions: {
parser: vueEslintParser,
parserOptions: {
parser: tseslint.parser,
},
+ globals: {
+ ...eslintAutoImport.globals,
+ },
},
},
)
更新文件 src/vite-env.d.ts
src/vite-env.d.ts
/// <reference types="vite/client" />
+/// <reference types="../auto-imports.d.ts" />
+/// <reference types="../components.d.ts" />
declare module '*.vue' {
import {DefineComponent} from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
国际化配置
更新文件 src/App.vue
src/App.vue
<script setup lang="ts">
import {useCounterStore} from '@/store/modules/counter'
import {useI18n} from 'vue-i18n'
+import zhCn from 'element-plus/es/locale/lang/zh-cn'
+import en from 'element-plus/es/locale/lang/en'
const counterStore = useCounterStore()
const {t, locale} = useI18n()
</script>
<template>
+ <ElConfigProvider :locale="locale === 'zh' ? zhCn : en">
<h1>Vue3 Element Plus Ts</h1>
+ <ElDatePicker />
<button
class="border p-2 rounded-md"
@click="locale = locale !== 'zh' ? 'zh' : 'en'"
>
切换语言 {{ locale }}
</button>
<div>
{{ t('message') }}
</div>
<button class="border p-2 rounded-md" @click="counterStore.increment()">
count加1
</button>
<div class="flex gap-2">
<span>{{ counterStore.count }}</span>
<span>{{ counterStore.doubleCount }}</span>
</div>
<div class="flex gap-2">
<RouterLink to="/t1" class="underline text-teal-600"
>TestA.vue</RouterLink
>
|
<RouterLink to="/t2" class="underline text-teal-600"
>TestB.vue</RouterLink
>
</div>
<RouterView />
+ </ElConfigProvider>
</template>
将设置语言提取 hooks,创建文件 src/hooks/useLocaleSwitcher.ts
src/hooks/useLocaleSwitcher.ts
import {useI18n} from 'vue-i18n'
import {Language} from 'element-plus/lib/locale/index.js'
import zhLocale from 'element-plus/es/locale/lang/zh-cn'
import enLocale from 'element-plus/es/locale/lang/en'
const locales = {
en: 'English',
zh: '中文',
}
const elementLocales: {[key: string]: Language} = {
en: enLocale,
zh: zhLocale,
}
export const useLocaleSwitcher = () => {
const {locale} = useI18n()
const currentLocale = ref(locale.value)
const elementLocale = computed(() => elementLocales[locale.value])
const switchLocale = (lang: string) => {
locale.value = lang
currentLocale.value = lang
}
return {
currentLocale,
elementLocale,
locales,
switchLocale,
}
}
更新文件 src/App.vue
src/App.vue
<script setup lang="ts">
import {useCounterStore} from '@/store/modules/counter'
import {useI18n} from 'vue-i18n'
+import {useLocaleSwitcher} from '@/hooks/useLocaleSwitcher'
-import zhCn from 'element-plus/es/locale/lang/zh-cn'
-import en from 'element-plus/es/locale/lang/en'
const counterStore = useCounterStore()
+const {currentLocale, elementLocale, locales, switchLocale} =
+ useLocaleSwitcher()
+const {t} = useI18n()
+const localeValue = ref()
</script>
<template>
+ <ElConfigProvider :locale="elementLocale">
<h1>Vue3 Element Plus Ts</h1>
<ElDatePicker />
- <button
- class="border p-2 rounded-md"
- @click="locale = locale !== 'zh' ? 'zh' : 'en'"
- >
- 切换语言 {{ locale }}
- </button>
+ <ElSelect v-model="localeValue" class="!w-[220px]" @change="switchLocale">
+ <template v-for="(value, key) in locales" :key="key">
+ <ElOption :label="value" :value="key" />
+ </template>
+ </ElSelect>
+ <div>{{ t('message') }} {{ currentLocale }}</div>
<button class="border p-2 rounded-md" @click="counterStore.increment()">
count加1
</button>
<div class="flex gap-2">
<span>{{ counterStore.count }}</span>
<span>{{ counterStore.doubleCount }}</span>
</div>
<div class="flex gap-2">
<RouterLink to="/t1" class="underline text-teal-600"
>TestA.vue</RouterLink
>
|
<RouterLink to="/t2" class="underline text-teal-600"
>TestB.vue</RouterLink
>
</div>
<RouterView />
</ElConfigProvider>
</template>
主题设置
安装 sass css的预处理器
$ npm add -D sass
创建文件 styles/element/index.scss
styles/element/index.scss
/* 只需要重写你需要的即可 */
@forward 'element-plus/theme-chalk/src/common/var.scss' with (
$colors: (
'primary': (
'base': green,
),
),
);
设置按需导入时自定义主题,更新文件 vite.config.ts
vite.config.ts
import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'
import {fileURLToPath} from 'node:url'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import {ElementPlusResolver} from 'unplugin-vue-components/resolvers'
// https://vitejs.dev/config/
export default defineConfig({
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
},
},
+ css: {
+ preprocessorOptions: {
+ scss: {
+ additionalData: `@use "@/styles/element/index.scss" as *;`,
+ },
+ },
+ },
plugins: [
vue(),
AutoImport({
imports: ['vue', 'vue-router'],
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [
+ ElementPlusResolver({
+ importStyle: 'sass',
+ }),
],
}),
],
})
更新文件 src/App.vue 查看效果
src/App.vue
//...
<template>
<ElConfigProvider :locale="elementLocale">
<h1>Vue3 Element Plus Ts</h1>
+ <ElButton type="primary">Button</ElButton>
<ElDatePicker />
//...
</ElConfigProvider>
</template>
暗黑模式
更新文件 src/main.ts
src/main.ts
import {createApp} from 'vue'
+import 'element-plus/theme-chalk/dark/css-vars.css'
import './style.css'
import App from './App.vue'
import router from './router'
import pinia from './store'
import i18n from './i18n'
const app = createApp(App)
app.use(router)
app.use(pinia)
app.use(i18n)
app.mount('#app')
使用 VueUse 动态切换暗黑模式
安装 VueUse
$ npm i @vueuse/core
更新文件 vite.config.ts
vite.config.ts
//...
// https://vitejs.dev/config/
export default defineConfig({
//...
plugins: [
vue(),
AutoImport({
+ imports: ['vue', 'vue-router', '@vueuse/core'],
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [
ElementPlusResolver({
importStyle: 'sass',
}),
],
}),
],
})
更新文件 src/App.vue 查看效果
src/App.vue
<script setup lang="ts">
//...
+const isDark = useDark()
+const toggleDark = useToggle(isDark)
</script>
<template>
<ElConfigProvider :locale="elementLocale">
<h1>Vue3 Element Plus Ts</h1>
+ <ElButton type="primary" @click="toggleDark()">切换暗黑模式 {{ isDark }}</ElButton>
<ElDatePicker />
//...
</ElConfigProvider>
</template>