Composition API 是 Vue3 推出後最大的特點,是 Vue 元件的另一種編寫方式。
那我們今天要與各位介紹的是,當 Vue2 的專案準備升級成 Vue3 時,應該如何改寫。又或者是在我們準備以 Vue3 撰寫專案時,應該如何起手呢?那就馬上來看看吧!
首先,讓我們先來看看 Vue2 的 Options API 結構:
export default {
props: {},
data() {
return {};
},
watch: {},
computed: {},
methods: {},
};
由上方的程式碼可以看到,Options API 讓我們在撰寫上多了一層制約,導致邏輯散落在各選項中,程式碼也因此變得難以理解,在閱讀上也因為難以分割造成困難。
與 Options API 不同的是,Vue3 的 setup 函式可以在裡面去定義我們所需要的東西,例如:data
、methods
、computed
、lifecycle
等。且會在元件尚未被建立之前執行,而使用的是 Composition API 的實際位置。setup 函式也可以回傳一個物件,物件中內容都將給予元件的其他部分:計算、方法、生命週期及元件的模板等等。
<script>
export default {
data() {
return {
};
},
};
</script>
在 Vue3 中,可以透過 reactive 的方式去建立響應式物件,或透過 ref 建立響應式變數。
reactive() 首先會接受一個普通物件,並將此作為參數,接著再回傳一個響應式的物件狀態,而此種響應式轉換則稱作為「深度轉換」。要注意的是 reactive 只接受 Object 及 Array 做監聽,而當我們在取資料時,並不會使用 .value
。
<template>
<div id="ithome_example">
<p>{{ name }}</p>
</div>
</template>
<script>
import { reactive } from "vue";
export default {
setup() {
const data = reactive({
name: "2022_ithome",
});
},
};
</script>
由此可見,data 在回傳物件時,是透過內部的 reactive 讓他成為響應是物件的。
ref() 是一個可以接受任何型別的參數,並回傳一個響應式且可變動的 ref 物件,而在物件中只會包含一個名為 value
的屬性,但要注意的是,ref 並不會對 Object 與 Array 的內部屬性做監聽。
補充一點,如傳入的型別是物件的話,內部會呼叫 reactive() 並將其轉換為響應式物件。
<template>
<div id="ithome_example">
<p>{{ name }}</p>
</div>
</template>
<script>
import { ref } from "vue";
export default {
setup() {
const name = ref("2022_ithome");
return { name };
},
};
</script>
假如我們 console.log (name) 的話,可以發現 Composition API 的 ref 是一個 Object,但若我們想改變 name 的值,就需要去更改他的 value。而 ref 除了可以當值來用,也可以把它當作一個 Vue 的節點。
msg.value = '2022_ithome_example'
以上,我們可以看到在定義資料的時候,會用 ref 或 reactive,那就有人疑問了:該如何選用呢? 其實在大多數的情況下兩者都是可以的,看個人習慣及團隊的協調。
當我們把將 ref 分配給響應式物件的 property 時,則 ref 物件就會自動解構。
import { ref, reactive } from 'vue';
const count = ref(1);
const data = reactive({});
data.count = count;
const obj = ref({});
obj.value.count = count;
但只有物件會去解構 ref ,陣列不會。所以陣列在給值時,一樣需要加上 .vaule
。
import { ref, reactive } from 'vue';
const arr = ref([]);
arr.value[0] = count;
arr.value[1] = count.value;
當我們在執行 setup 函式的時,元件的實體還尚未建立,而在 setup 函式裡的 this 並不是實體的引用。所以當我們想訪問 props
、attrs
、slots
、emit
時,則可以透過 setup
函式提供的兩個參數來訪問:
props 是響應式物件,可用來在 setup 函式中去取得父元件所傳遞的 prop。
<script>
export default {
props: ['name'],
setup(props) {
console.log(props.name);
},
};
</script>
要注意的是,如想使用 ES6 的解構 const { msg } = props,則會失去響應性。因此 Vue3 提供了我們 toRefs
的方法,讓我們能夠將響應式的物件轉換成普通的物件,並且將每個 property 轉成指向原始物件 property 的 ref 物件。
import { toRef } from 'vue';
export default {
props: ['msg', 'name'],
setup(props) {
const { name, msg } = toRefs(props);
},
};
舉個例子,這是我們在 Component 的 HTML:
<HelloWorld name="Hello World"/>
那在 HelloWorld.vue 的組件中的 Props 的值,就可以如下寫法去接應:
export default {
props: ['name'],
setup(props) {
const data = props.name;
console.log(data);
}
}
這樣子我們的 console.log 就會輸出 Hello World 囉!這樣是不是清楚了許多
那當然的,我們也能將 Props 轉換為 Ref:
import { toRef } from 'vue'
export default {
props: ['name'],
setup(props) {
const name = toRef(props, 'title');
console.log(name.value);
}
}
而從這邊可以看到以上程式碼我們使用的是 toRef,既然使用了自然也要跟各位稍微介紹一下呢!
toRef() 與 ref() 都可用來建立響應式資料的,但 ref 會複製一份新的資料,而 toRef() 則只會保持對其源頭的 property 進行響應式連接,即使 property 不存在,toRef() 也會回傳一個可用的 Ref 物件。
toRefs 雖然與 toRef 只差了一個字母,但兩個功能是不同的喔!toRefs 可以將響應式物件轉成普通物件,並且將每個 property 轉換成指向原始物件所對應 property 的 Ref 物件。比如說,我們如果使用 ES6 去解構 const { msg } = props
的話,就會失去響應性。這時候就可以讓 toRefs 幫我們解決了。
watch 顧名思義,監聽的意思。可用來監聽某個數據,並觸發相對應的處理。而在 watch 的物件下,我們可以使用 key
:value
的方式去定義我們想觀察的值以及其相對應的操作。而當我們資料發生變化時,便可以呼叫函式,而這時候的函式就會新增兩個傳入的參數:改變前的值
與改變後的值
,我們就可以利用此函式去做跟此資料變動相關的處理。
<script>
export default {
watch: {
test: {
name: function () {
console.log("2022_ithome");
},
},
},
};
</script>
而 watch 在 Vue 中有兩種使用方式:
$watch
:Vue 實體的函數,可使用此函數去註冊監聽器watch
:Vue 實體的屬性,屬性設置的物件在實體建立時會呼叫 $watch 註冊監聽器$watch 是註冊監聽器的函數,而 watch 則是提供給開發者在實體上更方便的去設置監聽器,而其實 watch 本身也是使用 $watch 註冊監聽器的。