從 React 轉成 Vue 馬上就踩雷。
簡述
當初是看 官方文件 來配置的,不過我自己覺得實在是寫得有點亂,因為當時的主流都是以 Vite 為主,而 Vue-CLI 的相關資料就顯得少蠻多的。
總之呢,這篇會以 Vue-CLI 的角度來寫一篇更好懂的教學來記錄一下,也順便解釋一些基本觀念。
前備知識
當初在配置時花了一段時間才搞好,這是因為 Vue 跟 React 在引入 UI 元件的方式有點不太一樣,所以我想先在這邊解釋一下差別。
首先在 React 中如果要使用 Mui,我們通常是這樣做:
1 2 3 4 5 6
| import * as React from 'react' import Button from '@mui/material/Button'
function App() { return <Button variant='contained'>Hello World</Button> }
|
React 的做法是「直接在元件中把 UI 元件引入」。以我自己的角度而言這是很直覺的方式,畢竟就是直接 import 進來用嘛?
而 Vue 除了直接在 SFC 中引入以外,還有一種更簡潔的做法,這邊拿 element-plush 來舉例。
直接在 SFC 中引入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <template> <nav> <el-button type="primary">Hello</el-button> </nav> <router-view /> </template>
<script> import { ElButton } from 'element-plus'
export default { components: { ElButton } } </script>
|
雖然這樣做也可行,不過你應該會更常看到下面這種寫法:
1 2 3 4 5 6 7 8 9 10
| import { createApp } from 'vue' import App from './App.vue' import { ElButton } from 'element-plus' import 'element-plus/dist/index.css'
const app = createApp(App)
app.component(ElButton.name, ElButton) app.use(router) app.mount('#app')
|
這個作法是直接「在 Vue 實體上註冊(Register)全域元件」。
意思就是所有的 SFC 中可以直接使用 <el-button>
,不用再做引入的動作。
這應該算是 Vue 的特色吧,雖然一開始覺得這好搞剛,不過多寫一段時間後就會覺得這樣其實也不錯。
總之如果你是用 Vue 的 UI library,你基本上都會看到第二種寫法,只是想解釋一下這背後的原因是什麼。
安裝依賴項目
這邊先用 Vue-CLI 的 create <project>
建立好以後再來安裝:
引入
引入的方式有兩種,分別為「全部引入」跟「按需引入」。
這裡順便提一個小知識,我們在 import 套件時雖然都會寫成 import { ElButton } from 'element-plus'
這樣的形式,不過實際上的路徑是對應到 node_modules/element-plus/lib/index
這個位置。
總之如果等一下引入部分你發現有問題,可以試著檢查看看是不是路徑不對,通常有 90% 都是因為這樣子,試著自己 debug 看看吧!
全部引入
意思就是一次把所有元件都引入:
1 2 3 4 5 6 7 8 9 10 11 12 13
| import { createApp } from 'vue' import App from './App.vue'
import 'element-plus/dist/index.css'
import ElementPlus from 'element-plus'
const app = createApp(App)
app.use(ElementPlus) app.use(router) app.mount('#app')
|
不管是 CSS 還是元件都直接全部引入,接著就可以直接在元件中使用了。這招最簡單,但缺點就是你如果你用的數量不多的話會顯得浪費。
按需引入
這邊是我覺得文件中寫的最麻煩的地方,一開始就要你安裝一堆套件跟調整 webpack。
這邊我想先介紹一下最簡單的方式,這邊你不需要安裝任何東西,只要先這樣寫就好:
1 2 3 4 5 6 7 8 9 10 11 12 13
| import { createApp } from 'vue' import App from './App.vue' import router from './router' import { ElButton } from 'element-plus'
import 'element-plus/dist/index.css'
const app = createApp(App)
app.component(ElButton.name, ElButton) app.use(router) app.mount('#app')
|
其實就是把需要的元件拿出來用而已,而不是整包拿出來。
不過這邊應該會注意到 CSS 的部分是引入 index.css
,有沒有辦法只引入 Elbutton
會用到的 CSS 就好?
有,這個就是文件裡面要你安裝各種套件跟調整設定的原因。如果你沒有很在意「體積」的問題的話,底下的部分你可以略過,因為完全沒有必要。
總之這樣子做的用意是降低容量,根據我實測的結果來看最多可以減少個 100KB 左右吧(看你實際用的多或少),所以這個就看真的看個人需求來決定了
首先來安裝新的包:
1
| npm i unplugin-element-plus -D
|
接著調整 vue.config.js
:
1 2 3 4 5 6 7 8 9 10
| module.exports = defineConfig({ configureWebpack: { plugins: [ require('unplugin-element-plus/webpack')({ }) ] } })
|
附註:關於 options 的部分想知道更多可以參考文件。
這個包的用途就是在我「引入元件時也自動引入對應的 CSS 檔案」,像這樣:
1 2 3 4 5 6
| import { ElButton } from 'element-plus'
import { ElButton } from 'element-plus' import 'element-plus/es/components/button/style/css'
|
看到這邊你應該也理解為什麼要有這個套件了吧?畢竟妳不可以每用一個元件就去找出對應的 CSS 來引入,怎麼想都太麻煩了,所以才會寫成套件來處理。
OK,到這邊以後基本上就配置好環境了,最後會來討論一下優化的部分。
最後的優化
看到這邊你應該已經知道怎麼「按需引入」需要的東西了,不過我想介紹一個更優雅的寫法,畢竟你應該不會想像這樣子把所有東西都寫在 main.js
裡:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import { createApp } from 'vue' import App from './App.vue' import router from './router' import { ElInput, ElForm, ElFormItem, ElButton, ElMessage, ElNotification } from 'element-plus'
const app = createApp(App)
app.component(ElInput.name, ElInput) app.component(ElForm.name, ElForm) app.component(ElFormItem.name, ElFormItem) app.component(ElButton.name, ElButton)
app.use(ElMessage) app.use(ElNotification)
app.use(router) app.mount('#app')
|
附註:plugin 指的是像 ElNotification
這種屬於 function 而不是元件的東西。
所以你可以建立一個 src/plugins/elementui.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import { ElInput, ElForm, ElFormItem, ElButton, ElMessage, ElNotification, } from 'element-plus'
export const elComponents = [ElInput, ElForm, ElFormItem, ElButton, ...]
export const elPlugins = [ElMessage, ElNotification, ...]
|
接著在 main.js
的時候就可以乾淨很多:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import { createApp } from 'vue' import App from './App.vue' import router from './router' import { elComponents, elPlugins } from './plugin/elementui'
const app = createApp(App)
elComponents.forEach((c) => { app.component(c.name, c) })
elPlugins.forEach((p) => { app.use(p) })
app.use(router) app.mount('#app')
|