該系列是為了讓看過Vue官方文件或學過Vue但是卻不知道怎麼下手去重構現在有的網站而去規畫的系列文章,在這邊整理了許多我自己使用Vue重構很多網站的經驗分享給讀者們。
Vue3 的 Composition Api 可以說是改變了原本的 Option Api 撰寫上面的方式,還有撰寫 Vue 上面的一些思維的變動。
所以今天如果我們接手了一個 Vue2 的專案要升級成 Veu3 Composition Api 的話,我們可以先從甚麼地方下手,會需要注意那些地方,然後要怎麼去改寫 Option Api,我們馬上來看一下。
跟以往的 Option Api 不同,我們可以在 setup 函式裡面去定義我們所有的東西,包含data
、methods
、computed
、lifecycle
等方法。
<script>
export default {
setup(){
return {}
}
}
</script>
我們在改寫的時候會先來看一下有多少被定義的資料,這邊是我們在 Option Api 裡面定義的資料的部分。
<script>
export default {
data(){
return {
userData: {
name: '',
age: '',
address: '',
},
isOpen: false,
products: []
}
}
}
</script>
我們接下來來用 Vue3 的方式來改寫 ,就會像這樣。
<script>
import { ref, reactive } from "vue";
export default {
setup() {
const isOpen = ref(false)
const products = ref([])
const userData = reactive({
name: '',
age: '',
address: '',
})
return {}
},
};
</script>
在這邊你會看到我定義資料是用 ref
跟 reactive
來定義的,關於我們該如何選用 ref
跟 reactive
呢 ? 在大多數的情況下兩者皆可以互相替換使用,主要取決於個人喜好或是團隊習慣,根據具體情況來決定要使用哪個好,關於 ref
跟 reactive
的差異我們來看一下 :
ref
: 可以使用任何型態的資料,但是不會對 Object
或是 Array
內部的屬性做監聽。reactive
: 只接受 Object
或 Array
,可以做深層的監聽,以及取資料的時候不用使用 .value
,但是如果對 reactive 的 Object 使用解構的方式取得內容,就會失去了 Vue 更新綁定的機制。我自己個人一般的情況下能盡量使用 ref
就使用ref
,可以更精準地去控制資料的更新,很多人不習慣用 .value
的方式,但是 .value
的方式可以讓開發者更明確知道這段 code 再進行資料的更新。
更多具體的細節可以參考我之前寫的這篇文章 ref 跟 reactive 我該怎麼選 !?
一般我們要定義 methods 會在 methods 這個欄位裡面去定義它的 function,然後要 get
、set
可以透過 this
來使用,這個 this
就是指向 Vue 本身。
<script>
export default {
data(){
return {
userData: {
name: '',
age: '',
address: '',
},
isOpen: false,
products: []
}
},
methods: {
handleTroggle(){
this.isOpen = !this.isOpen
},
setProducts(prod){
this.products = prod
},
showUserKey(){
this.userData.name = 'mike'
console.log(this.userData.name)
}
}
}
</script>
但是改成 Composition Api 的方式就不需要寫在 methods 裡面,也不需要管 this 指向的部分,整體下來看起來乾淨很多。
<script>
import { ref, reactive } from "vue";
export default {
setup() {
const isOpen = ref(false)
const products = ref([])
const userData = reactive({
name: '',
age: '',
address: '',
})
const handleTroggle = () => {
isOpen.value = !isOpen.value
}
const setProducts = (prod) => {
products.value = prod
}
const showUserKey = () => {
userData.name = 'mike'
console.log(userData.name)
}
return {}
},
};
</script>
以前我們會把共用的 function 或是 data 給放到 mixins,但是 mixins 最讓人詬病的是對於來源的查找很不明確,只能靠 coding style 來做區別,所以我們要透過 Composition Api 的方式來處理共用的 function 。
先新增一個 myMixin.vue
的檔案
// myMixin.vue
<script>
export default {
data(){
return {
point: 0
}
},
methods: {
addPoint() {
this.point += 1
}
}
}
</script>
然後再我們的 Component 去載入 myMixin.vue
// app.vue
<script>
import myMixin from "./myMixin.vue";
export default {
mixins: [myMixin],
data(){
...
},
methods: {
...
}
}
</script>
<template>
<div id="app">
<h1>Point: {{ point }}</h1>
<button @click="addPoint">click</button>
</div>
</template>
上面就是一般我們使用 mixins
的方式,雖然方便,但是如果多個 Component 的引入跟使用也會造成管理上的不方便,所以接下來我們使用 composition Api 來包裝它。
先新增一個名叫 useAddPoints.js
的檔案
import { ref, readonly } from "vue"
export function useAddPoints(){
const point = ref(0)
const addPoint = () => {
point.value += 1
}
return {
point: readonly(point),
addPoint
}
}
這邊使用了 readonly
最主要是希望這個傳出去的值是只可以get
讀取的,所以在這邊把它給用 readonly
包起來,關於 readonly
的細節可以參考官方的文件
官方文件 : https://v3.vuejs.org/api/basic-reactivity.html#readonly
然後要使用的話就像是這樣,非常的簡單明瞭,完全解決了使用 mixins
上面來源不清楚的問題。
<script>
import { useAddPoints } from "../composition/useAddPoints.js"
export default {
setup() {
const { point, addPoint } = useAddPoints();
return {
point,
addPoint
}
},
};
</script>
<template>
<div id="app">
<h1>Point: {{ point }}</h1>
<button @click="addPoint">click</button>
</div>
</template>
我們在 Option Api 裡面有許多的 lifecycle
可以用,但是到了 composition Api
裡面就有了一些變化,所以今天讓我們來稍微看一下這些變化,也好在轉移程式碼的時候避免發生一些問題。
<script>
export default {
beforeCreate(){},
created(){},
beforeMount(){},
mounted(){},
updated(){},
destroyed(){}
}
</script>
但是在 composition Api
裡面我們要從 vue 裡面把 lifecycle
取出來在 setup
使用。
<script>
import {
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onUnmounted
} from "vue"
export default {
setup() {
onBeforeMount(()=> {})
onMounted(()=> {})
onBeforeUpdate(()=> {})
onUpdated(()=> {})
onUnmounted(()=> {})
return {}
},
};
</script>
不過這邊要特別注意,原本 Veu2 裡面 destroyed
這個生命週期函式再 Vue3 裡面 改名叫做 onUnmounted
,然後原本的 beforeCreate
、created
沒了, 現在的 setup
這個函式就等同於 beforeCreate
、created
這兩個效果一樣,合再一起了。
更多完整的生命週期函式可以參考官方文件的部份
https://v3.vuejs.org/guide/composition-api-lifecycle-hooks.html#lifecycle-hooks
所以我今天如果是要在 created
裡面去打 API,我就可以直接在 setup
裡面去做操作
<script>
import { ref } from 'vue'
import axios from "axios"
export default {
setup() {
const userData = ref([])
// 等同於再 created 執行
axios.get("https://test.demo.com/api/getUser").then((res)=> {
userData.value = res.data
})
return {
userData
}
},
};
</script>
或是今天你要移除原生 JS 監聽的時候,就可以改用 onUnmounted
<script>
import { onMounted, onUnmounted } from 'vue'
import axios from "axios"
export default {
setup() {
const handleWinReSize = (e) => {
console.log(e)
}
onMounted(()=> {
window.addEventListener("resize", ,handleWinReSize)
})
// 等同於 Vue2 的 destroyed
onUnmounted(()=> {
window.removeEventListener("resize", ,handleWinReSize)
})
return { }
},
};
</script>
以前在 Option Api 上面的時候都要透過 this 的方式來取得 props 還有使用 emit,但是在 Composition Api 裡面可以統一透過 setup 函式來取得這兩個物件。
定義好 props 傳入的內容,我們就可以從 setup 正確的取得 props ,它會從 setup 的第一個參數傳入。
<script>
import { onMounted } from 'vue'
export default {
props: {
userType: {
type: String,
default: "user"
}
},
setup(props) {
onMounted(()=> {
console.log(props.userType)
})
return { props }
},
};
</script>
<template>
<h1>{{ props.userType }}</h1>
</template>
emit 再 setup 的第二個參數的物件裡面,我們可以透過解構的方式直接取出,然後使用。
<script>
export default {
emits: ['userName'],
setup(props, { emit }) {
const getUserName = (name) => {
emit("userName", name)
}
return { getUserName }
},
};
</script>
<template>
<button @click="getUserName('mike')">mike</button>
<button @click="getUserName('jacky')">jacky</button>
<button @click="getUserName('andy')">andy</button>
<button @click="getUserName('scars')">scars</button>
<button @click="getUserName('ash')">ash</button>
</template>
重構這件事情不是一個小工程,它裡面有很多需要注意的細節在裡面,包括如何讀懂人家的邏輯以及理解這個功能開發上面的前因後果,還有就是你的經驗的展現,各種問題、各種情境,除了程式碼語法版本上面的差異外,還有很多都是要下功夫的,再後面的章節,我會再一一的跟大家介紹關於重構專案上面其他需要注意的地方,還有我的思考規劃的方式,以及選用技術的考量等。
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
請問<script setup>
的使用與內文中的定義
<script>
...
export default {
setup() {
const { point, addPoint } = useAddPoints();
return {
point,
addPoint
}
},
};
</script>
在使用上有什麼差別呢?
內文中的方式像是optionAPI與compositionAPI的結合使用方式
正在compositionAPI學習中..看到這裡有點苦手
之前回應被隱藏了...
script setup 跟現在範例的其實是一樣的,只是 這是語法糖,如果不是用語法糖的話,就是我現在demo code的樣子!