15 個 Vue3 全家桶開發的避坑經驗

作者:刪庫不跑路

鏈接:https://juejin.cn/post/7146236358908968968

最近入門 Vue3 並完成 3 個項目,遇到問題蠻多的,今天就花點時間整理一下,和大家分享 15 個比較常見的問題,基本都貼出對應文檔地址,還請多看文檔~ 已經完成的 3 個項目基本都是使用 Vue3 (setup-script 模式) 全家桶開發,因此主要分幾個方面總結:

一、Vue3

1. Vue2.x 和 Vue3.x 生命週期方法的變化

文檔地址:v3.cn.vuejs.org/guide/composition-api-lifecycle-hooks.html

Vue2.x 和 Vue3.x 生命週期方法的變化蠻大的,先看看:

目前 Vue3.x 依然支持 Vue2.x 的生命週期,但不建議混搭使用,前期可以先使用 2.x 的生命週期,後面儘量使用 3.x 的生命週期開發。

由於我使用都是 script-srtup模式,所以都是直接使用 Vue3.x 的生命週期函數:

// A.vue\
<script setup lang="ts">\
import { ref, onMounted } from "vue";\
let count = ref<number>(0);\
\
onMounted(() => {\
count.value = 1;\
})\
</script>

每個鉤子的執行時機點,也可以看看文檔:https://v3.cn.vuejs.org/guide/instance.html

2. script-setup 模式中父組件獲取子組件的數據

文檔地址:v3.cn.vuejs.org/api/sfc-script-setup.html#defineexpose

這裏主要介紹父組件如何去獲取子組件內部定義的變量,關於父子組件通信,可以看文檔介紹比較詳細:https://v3.cn.vuejs.org/guide/component-basics.html

我們可以使用全局編譯器宏defineExpose宏,將子組件中需要暴露給父組件獲取的參數,通過 {key: vlaue}方式作爲參數即可,父組件通過模版 ref 方式獲取子組件實例,就能獲取到對應值:

// 子組件\
<script setup>\
let name = ref("pingan8787")\
defineExpose({ name }); // 顯式暴露的數據,父組件纔可以獲取\
</script>\
\
// 父組件\
<Chlid ref="child"></Chlid>\
<script setup>\
let child = ref(null)\
child.value.name //獲取子組件中 name 的值爲 pingan8787\
</script>

注意

3. 爲 props 提供默認值

definedProps 文檔:v3.cn.vuejs.org/api/sfc-script-setup.html

前面介紹 script-setup 模式提供的 4 個全局編譯器宏,還沒有詳細介紹,這一節介紹 definePropswithDefaults。使用 defineProps宏可以用來定義組件的入參,使用如下:

<script setup lang="ts">\
let props = defineProps<{\
schema: AttrsValueObject;\
modelValue: any;\
}>();\
</script>

這裏只定義props屬性中的 schemamodelValue兩個屬性的類型, defineProps 的這種聲明的不足之處在於,它沒有提供設置 props 默認值的方式。

其實我們可以通過 withDefaults 這個宏來實現:

<script setup lang="ts">\
let props = withDefaults(\
defineProps<{\
schema: AttrsValueObject;\
modelValue: any;\
}>(),\
{\
schema: [],\
modelValue: ''\
}\
);\
</script>

withDefaults 輔助函數提供了對默認值的類型檢查,並確保返回的 props 的類型刪除了已聲明默認值的屬性的可選標誌。

4. 配置全局自定義參數

文檔地址:v3.cn.vuejs.org/guide/migration/global-api.html

在 Vue2.x 中我們可以通過 Vue.prototype 添加全局屬性 property。但是在 Vue3.x 中需要將 Vue.prototype 替換爲 config.globalProperties 配置:

// Vue2.x\
Vue.prototype.$api = axios;\
Vue.prototype.$eventBus = eventBus;\
\
// Vue3.x\
const app = createApp({})\
app.config.globalProperties.$api = axios;\
app.config.globalProperties.$eventBus = eventBus;

使用時需要先通過 vue 提供的 getCurrentInstance方法獲取實例對象:

5. v-model 變化

文檔地址:v3.cn.vuejs.org/guide/migration/v-model.html

當我們在使用 v-model指令的時候,實際上 v-bindv-on 組合的簡寫,Vue2.x 和 Vue3.x 又存在差異。

Vue2.x

在子組件中,如果要對某一個屬性進行雙向數據綁定,只要通過 this.$emit('update:myPropName', newValue) 就能更新其 v-model綁定的值。

script-setup模式下就不能使用 this.$emit去派發更新事件,畢竟沒有 this,這時候需要使用前面有介紹到的 defineProps、defineEmits 兩個宏來實現:

父組件使用的時候就很簡單:

6. 開發環境報錯不好排查

文檔地址:v3.cn.vuejs.org/api/application-config.html#errorhandler

Vue3.x 對於一些開發過程中的異常,做了更友好的提示警告,比如下面這個提示:

這樣能夠更清楚的告知異常的出處,可以看出大概是 <ElInput 0=......這邊的問題,但還不夠清楚。這時候就可以添加 Vue3.x 提供的全局異常處理器,更清晰的輸出錯誤內容和調用棧信息,代碼如下

這時候就能看到輸出內容如下:

一下子就清楚很多。當然,該配置項也可以用來集成錯誤追蹤服務 Sentry 和 Bugsnag。推薦閱讀:Vue3 如何實現全局異常處理?

7. 觀察 ref 的數據不直觀,不方便

當我們在控制檯輸出 ref聲明的變量時。

會看到控制檯輸出了一個 RefImpl對象:

看起來很不直觀。我們都知道,要獲取和修改 ref聲明的變量的值,需要通過 .value來獲取,所以你也可以:

這裏還有另一種方式,就是在控制檯的設置面板中開啓 「Enable custom formatters」選項。

這時候你會發現,控制檯輸出的 ref的格式發生變化了:

更加清晰直觀了。

這個方法是在《Vue.js 設計與實現》中發現的,但在文檔也沒有找到相關介紹

二、Vite

1. Vite 動態導入的使用問題

文檔地址:cn.vitejs.dev/guide/features.html#glob-import

使用 webpack 的同學應該都知道,在 webpack 中可以通過 require.context動態導入文件:

在 Vite 中,我們可以使用這兩個方法來動態導入文件:

該方法匹配到的文件默認是懶加載,通過動態導入實現,構建時會分離獨立的 chunk,是異步導入,返回的是 Promise,需要做異步操作,使用方式如下:

該方法是直接導入所有模塊,並且是同步導入,返回結果直接通過 for...in循環就可以操作,使用方式如下:

如果僅僅使用異步導入 Vue3 組件,也可以直接使用 Vue3 defineAsyncComponent API 來加載:

2. Vite 配置 alias 類型別名

文檔地址:cn.vitejs.dev/config/#resolve-alias

當項目比較複雜的時候,經常需要配置 alias 路徑別名來簡化一些代碼:

在 Vite 中配置也很簡單,只需要在 vite.config.tsresolve.alias中配置即可:

如果使用的是 TypeScript 時,編輯器會提示路徑不存在的警告⚠️,這時候可以在 tsconfig.json中添加 compilerOptions.paths的配置:

3. Vite 配置全局 scss

文檔地址:cn.vitejs.dev/config/#css-preprocessoroptions

當我們需要使用 scss 配置的主題變量(如 $primary)、mixin 方法(如 @mixin lines)等時,如:

我們可以將 scss 主題配置文件,配置在 vite.config.tscss.preprocessorOptions.scss.additionalData中:

如果不想使用 scss 配置文件,也可以直接寫成 scss 代碼:

三、VueRouter

1. script-setup 模式下獲取路由參數

文檔地址:router.vuejs.org/zh/guide/advanced/composition-api.html

由於在 script-setup模式下,沒有 this可以使用,就不能直接通過 this.$routerthis.$route來獲取路由參數和跳轉路由。當我們需要獲取路由參數時,就可以使用 vue-router提供的 useRoute方法來獲取,使用如下:

如果要做路由跳轉,就可以使用 useRouter方法的返回值去跳轉:

四、Pinia

1. store 解構的變量修改後沒有更新

文檔地址:pinia.vuejs.org/concepts/#using-the-store

當我們解構出 store 的變量後,再修改 store 上該變量的值,視圖沒有更新:

這時候點擊按鈕觸發 changeName事件後,視圖上的 name 並沒有變化。這是因爲 store 是個 reactive 對象,當進行解構後,會破壞它的響應性。所以我們不能直接進行解構。這種情況就可以使用 Pinia 提供 storeToRefs工具方法,使用起來也很簡單,只需要將需要解構的對象通過 storeToRefs方法包裹,其他邏輯不變:

這樣再修改其值,變更馬上更新視圖了。

2. Pinia 修改數據狀態的方式

按照官網給的方案,目前有三種方式修改:

  1. 通過 store.屬性名賦值修改單筆數據的狀態;

這個方法就是前面一節使用的:

  1. 通過 $patch方法修改多筆數據的狀態;

文檔地址:pinia.vuejs.org/api/interfaces/pinia._StoreWithState.html#patch

當我們需要同時修改多筆數據的狀態時,如果還是按照上面方法,可能要這麼寫:

上面這麼寫也沒什麼問題,但是 Pinia 官網已經說明,使用 $patch的效率會更高,性能更好,所以在修改多筆數據時,更推薦使用 $patch,使用方式也很簡單:

  1. 通過 action方法修改多筆數據的狀態;

也可以在 store 中定義 actions 的一個方法來更新:

使用時:

這三種方式都能更新 Pinia 中 store 的數據狀態。

五、Element Plus

1. element-plus 打包時 @charset 警告

項目新安裝的 element-plus 在開發階段都是正常,沒有提示任何警告,但是在打包過程中,控制檯輸出下面警告內容:

在官方 issues 中查閱很久:github.com/element-plus/element-plus/issues/3219%E3%80%82

嘗試在 vite.config.ts中配置 charset: false,結果也是無效:

最後在官方的 issues 中找到處理方法:

2. 中文語言包配置

文檔地址:element-plus.gitee.io/zh-CN/guide/i18n.html

默認 elemnt-plus 的組件是英文狀態:

我們可以通過引入中文語言包,並添加到 ElementPlus 配置中來切換成中文:

這時候就能看到 ElementPlus 裏面組件的文本變成中文了。

總結

以上是我最近從入門到實戰 Vue3 全家桶的 3 個項目後總結避坑經驗,其實很多都是文檔中有介紹的,只是剛開始不熟悉。也希望大夥多看看文檔咯~

Vue3 script-setup 模式確實越寫越香。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/5MWeksIlAC-aJxvn5V0vBw