該系列是為了讓看過Vue官方文件或學過Vue但是卻不知道怎麼下手去重構現在有的網站而去規畫的系列文章,在這邊整理了許多我自己使用Vue重構很多網站的經驗分享給讀者們。
我常常在重構專案的時候會看到前人寫的一些關於 vue 的 code 讓人摸不著頭緒,以及滿頭問號的情況,今天我將把一些我常常看到覺得不必要的寫法以及可以改善的 code 做個比較,讓大家在寫 code 的時候可以多多注意不要寫出讓人滿頭問號的程式碼。
這是我在很多專案常見到的 methods 的寫法
// option api style from vue-cli
methods: {
init: function() {
let that = this;
axios.get("https://test.api/data").then(function(res){
that.resVal = res.data
})
}
}
這個寫法不能說不能 work,只不過不是最理想的寫法,首先
在 Vue cli 裡面寫 methods 的時候,就可以採用 es6 寫法去掉 :function()
直接 init()
就好。
使用其他第三方工具的時候,call back function 應該使用 ES6 的箭頭函式 ( arrow function ),使用箭頭函式就不需要去外面宣告一個 that 塞入this ,因為箭頭函示內部是沒有 this 的指向,所以會往外部查找,就會直接指向 Vue。
// option api style from vue-cli
methods: {
init() {
axios.get("https://test.api/data").then((res)=>{
this.resVal = res.data
})
}
}
天阿!太多人分不清楚什麼時候應該用 let
還是 const
,所以乾脆一律 let
到底,我們來看一下什麼東西應該let
什麼應該 const
。
methods: {
loginUser (){
let url = "/api/login";
let postData = {
name: this.name,
password: this.password,
phone: this.phone,
};
axios.post(url, postData).then((res)=> {
console.log("login success");
})
}
}
這是一個很簡單的使用 API post 來進行登入的 function,你會看到這邊的 url 還有要 post 出去的 data 都是使用let 進行宣告,我們來分析一下,首先 let 除了是以大括號為界,具有scoped
的效果,也具有可以修改的特性,你可以隨意地修改它裡面的 value ,例如下面這種操作都是可以的
let a = 1;
console.log(a);
a = "mike"
console.log(a);
但是我們有些變數是不需要被修改的,例如我們的範例一樣,我們的 url 就是一個 API 的路徑,它是不會被修改的,所以這邊我們就應該用 const
來宣告,而不是 let
,我們的 postData 其實也是一樣的,它是最後將所需要的值給組合起來 post 出去的,所以他也應該用 const
。
const url = "/api/login";
const postData = {
name: this.name,
password: this.password,
phone: this.phone,
};
關於 let 跟 const 的更多差異我相信網路上已經有很多這類的比較資料,這邊我就不再多做贅述。
這邊附上 MDN 的文件,還不了解的可以看一下。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#declarations
我看過好多人在寫 Component 的時候 props 都這樣寫,直接用一個 Array 包起來這樣
<script>
export default {
props: ["usertype", "handleOpenNav", 'count'],
...
}
</script>
但是我們可以看到 Vue 官方的 style guide 上面有明確的講說這樣是你在一開始設計 component 的時候用,當你的資料類型都確定完成後,要改成以下寫法。
<script>
export default {
props: {
usertype: {
type: String
},
handleOpenNav: {
type: Function
},
count: {
type: Number
}
},
...
}
</script>
這樣我們就可以去定義我們傳入的 props 的類型,也可以一眼就知道這個傳入的 props 類型是什麼,即便傳錯了類型的參數,log 也會報錯跟你說參數傳入錯誤了。
props style guide
https://v3.vuejs.org/style-guide/#prop-definitions-essential
然後我最推薦的寫法是除了加上 type 以外,還加入了 default 的處理 props 的方式。
<script>
export default {
props: {
usertype: {
type: String,
default: "default"
},
handleOpenNav: {
type: Function,
default: ()=> {}
},
count: {
type: Number,
default: 0
}
},
...
}
</script>
你可以看到我給了每一個 props 一個 default value,如果今天我沒有傳入的 props,它就會當成你 default 設定的那個 value 來使用,這樣可以避免掉很多如果你沒有傳入參數的時候,也可以透過這種方式來處理畫面上面的狀態,讓它有預設的 status。
https://v3.vuejs.org/style-guide/#empty-lines-in-component-instance-options-recommended
這邊我列幾個很容易寫錯了的 props default 給大家參考
<script>
export default {
props: {
handleOpenNav: {
type: Function,
default: ()=> {}
},
userList: {
type: Array,
default: ()=> ([])
},
fetchData: {
type: Object,
default: ()=> ({})
},
},
...
}
</script>
最常看到寫錯的就是 Function
、Array
、Object
這三個 type,你仔細看 Function
、Array
都是需要透過函式的方式去回傳,而不是直接定義一個空的 []
或是 {}
,這點要特別注意。
關於 props 定義的部分可以看這份文件
https://v3.vuejs.org/guide/component-props.html#prop-validation
我們很常會搞不清楚什麼時候應該用 Computed 什麼時候應該用 Methods 來處理資料的回傳,我們先來看一下Computed 的部分,在我們前一篇的文章有提到
computed 是一個計算屬性,設計它的初衷是用於簡單運算的,在模板中放入太多的邏輯會讓模板過重且難以維護,所以會需要透過computed 來重新處理過那些複雜的資料,官方文件有提到說
computed 屬性是基於Vue綁定的資料依賴關係緩存的
這意味者 computed 只在透過Vue綁定的資料發生改變時它們才會重新去執行處理計算,所以今天你的資料只要是Vue綁定的資料,都可以被計算處理過。
我們來看以下例子
<script>
export default {
props: {
showType: {
type: String,
default: 'not_login',
},
},
setup(props) {
const isShowBtnStatus = () => props.showType === "not_login";
return { isShowBtnStatus };
},
};
</script>
<template>
<a v-if="isShowBtnStatus()">登入</a>
<a v-if="!isShowBtnStatus()">登出</a>
<a v-if="!isShowBtnStatus()">觀看紀錄</a>
</template>
我們可以看到這邊 isShowBtnStatus 這個 methods去判斷我的 props,然後在 template 的地方去call 這個 methods,讓它回傳狀態,但其實我們應該要改成使用 computed 才對
<script>
import { computed } from "vue";
export default {
props: {
showType: {
type: String,
default: 'not_login',
},
},
setup(props) {
const isShowBtnStatus = computed(() => props.showType === "not_login");
return { isShowBtnStatus };
},
};
</script>
<template>
<a v-if="isShowBtnStatus">登入</a>
<a v-if="!isShowBtnStatus">登出</a>
<a v-if="!isShowBtnStatus">觀看紀錄</a>
</template>
透過 computed 的方式可以讓資料達到緩存的效果,資料沒變就不會重新計算,除非今天你是要傳參數進去做計算,才需要選擇 methods 來return value.不然的話大部分的計算需求使用 computed 是比較恰當的!
很多在剛開始升級 Vue3 的朋友會因為還不習慣使用 composition api 而寫出以下的 code
import { ref } from 'vue'
export default {
props: {
user: {
type: String,
required: true
}
},
data () {
return {
filters: {},
searchQuery: ''
}
},
setup (props) {
const repositories = ref([])
const handleLog = () => {
console.log("use")
}
return {
repositories,
handleLog
}
},
watch: {
searchQuery(){ ... }
},
mounted () {
this.handleLog()
}
}
你會發現這邊把 Composition Api 跟 Option Api 給混再一起,變得很奇怪,定義data的地方變成了兩個,使用 methods 的時候一下在Option Api 裡面要使用 this 但是在 setup 裡面又不用,整個變得難以閱讀且凌亂,在使用 Composition Api 的時候就可以全部解決這樣的問題。
import { ref, reactive, watch, onMounted } from 'vue'
export default {
props: {
user: {
type: String,
required: true
}
},
setup (props) {
const repositories = ref([])
const searchQuery = ref("")
const filters = reactive({})
const handleLog = () => {
console.log("use")
}
watch(searchQuery, (newVal)=> {
console.log("newVal=>", newVal)
})
onMounted(()=> {
handleLog()
})
return {
repositories,
handleLog
}
}
}
你看我把原本 Option Api 的部分全部改成 Composition Api 是不是清爽許多,官方也是建議 Composition Api 跟 Option Api 則一選擇就好,不推薦兩種寫法混用,導致你的 code 看起來很混亂。
更多關於 Composition Api 的內容
https://v3.vuejs.org/guide/composition-api-introduction.html#introduction
好啦!今天就到這邊啦~明天見!
Ps. 購買的時候請登入或註冊該平台的會員,然後再使用下面連結進入網站點擊「立即購課」,這樣才可以讓我獲得更多的課程分潤,還可以幫助我完成更多豐富的內容給各位。
我有開設了一堂專門針對Vue3從零開始教學的課程,如果你覺得不錯的話,可以購買我課程來學習
https://hiskio.com/bundles/9WwPNYRpz?s=tc
那如果對於JS基礎不熟的朋友,我也有開設JS的入門課程,可以參考這個課程
https://hiskio.com/bundles/b9Rovqy7z?s=tc
Mike 的 Youtube 頻道
Mike的medium
MIke 的官方 line 帳號,好友搜尋 @mike_cheng
Hi 老師~第一點重構完的 code
that.resVal = res.data
應該是寫錯了,要改成
this.resVal = res.data
在寫的時候沒有注意到,謝謝幫我抓錯誤