有一陣子沒有寫部落格了,自從上工後第一份專案準備上線加上其他私事後,技術學習如 Vue SSR 解決方案 nuxt.js 、Vanilla JS 及前端相關知識等等的都是斷斷續續沒規劃地(想到才)學,昨天看到了神Q超人的這篇文,才驚覺自己已經很久沒有寫 Medium 了
Vue3 在兩天前正式釋出了,之前就一直常常看到 composition API 這個關鍵字,藉著這個時間點稍微了解了其使用方式,簡略做個筆記。
Composition API 只是 Vue3 中另一種編寫組件的方法 ,在 Vue3 中仍然可使用 Vue2 編寫組件的方法,其好處如下:
- 提供更好的 TypeScript 支持
- 組件太大,需要依功能分類時可使用
- 需要跨組件使用程式碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vue v3</title>
<script src="https://unpkg.com/vue@next"></script>
</head><body>
<div id="app">
<h1>{{msg}}</h1>
<button @click="addExclamationMark()">Add !</button>
</div><script>
const { ref } = Vue;
const App = {
setup() {
const msg = ref("Hello Vue 3");
function addExclamationMark() {
msg.value += "!";
}
return {
msg,
addExclamationMark,
};
},
};
Vue.createApp(App).mount("#app");
</script>
</body>
</html>
首先,藉由 const { ref } = Vue;
取得 Vue 的 ref 方法
setup()
會在 Components
, Props
, Data
, Methods
, Computed Properties
和 Lifecycle Methods
前執行,並且不能在其中存取 this
如果在 setup
階段中把 msg
log 出來,看起來會是這樣:
因此在 addExclamationMark
需要在 msg.value
才能改變 msg
在模板中的值;當 Vue
在模板中發現 ref
時,它會自動暴露(expose)出其內部的值,因此在模板中僅透過 {{msg}}
便能取得 “Hello Vue 3”,最後透過 return
將值及函式回傳至模板。
使用計算屬性
若要在 Composition API 使用計算屬性,需先從 Vue
中取得 computed
const { ref, computed } = Vue;
撰寫計算屬性:
const exclamationMarkLength = computed(() => {
return msg.value.match(/!/g)?.length || 0;
});
並 return 讓模板可以存取
return {
// ...
exclamationMarkLength,
};
模組化地使用
我們可以像這樣將程式碼提取作為函式讓其可以重複使用
const App = {
setup() {
return helloVueFunc();
},
};function helloVueFunc() {
const msg = ref("Hello Vue 3");
const exclamationMarkLength = computed(() => {
return msg.value.match(/!/g)?.length || 0;
});function addExclamationMark() {
msg.value += "!";
}return {
msg,
addExclamationMark,
exclamationMarkLength,
};
}
若要使用多個函式,可這樣寫:
<div id="app">
<h1>{{msg}}</h1>
<button @click="addExclamationMark()">Add !</button>
<p>Add exclmation mark times: {{exclamationMarkLength}}</p>
<h2>To do List</h2>
<p v-for="(todo, index) in todos" :key="index">{{ todo }}</p>
</div>
<script>
const { ref, computed } = Vue;
const App = {
setup() {
return { ...helloVueFunc(), ...todoListFunc() };
},
};
function helloVueFunc() {
const msg = ref("Hello Vue 3");
const exclamationMarkLength = computed(() => {
return msg.value.match(/!/g)?.length || 0;
}); function addExclamationMark() {
msg.value += "!";
} return {
msg,
addExclamationMark,
exclamationMarkLength,
};
}
function todoListFunc() {
const todos = ref([
"Buy apples",
"Learn Vue 3",
"Watch It's okay not to be okay",
]); return {
todos,
};
} Vue.createApp(App).mount("#app");
</script>
這樣會碰到一個問題,函式太多的時候,很難辨別模板中的物件來自於哪個函式。也可以改成這樣寫:
setup() {
const {
msg,
addExclamationMark,
exclamationMarkLength,
} = helloVueFunc();
const { todos } = todoListFunc();
return { msg, addExclamationMark, exclamationMarkLength, todos };
},
生命週期
若想在 setup
中寫在生命週期中執行的程式碼,可以這樣寫:
const { onBeforeMount, onMounted } = Vue;const App = {
setup() {
onBeforeMount(() => {
console.log("Before Mount!");
});
onMounted(() => {
console.log("Mounted!");
});
};
在 setup
中無法使用 beforeCreate
及 created
,是因為 setup
是在 beforeCreate
後立即被呼叫,created
則在 setup
之後,可以直接將程式碼寫在相對的生命週期
watchEffect
假如我有一個 input
,當我輸入 input
時需要發出非同步請求
<div id="app">
<input type="number" v-model="searchInput" />
searchInput: {{searchInput}}
<ul>
<li v-for="(user, index) in users" :key="index">{{user}}</li>
</ul>
</div><script>
const { ref, watchEffect } = Vue; const App = {
setup() {
const searchInput = ref(1);
const users = ref([]); usersAPI
.getRandomUsersByNumber(searchInput.value)
.then((usersData) => (users.value = usersData)); return { searchInput, users };
},
}; // usersAPI Obj...Vue.createApp(App).mount("#app");
</script>
會發現 input
不論怎麼更動,users
都只有 setup
時發出請求回傳的值,這時候就可以使用 watchEffect
watchEffect(() => {
usersAPI
.getRandomUsersByNumber(searchInput.value)
.then((usersData) => (users.value = usersData));
});
當 searchInput
的值改變了,就會觸發 watchEffect
的回呼函式再次發出請求。也可以使用 watch
:
watch(searchInput, (val) => {
usersAPI
.getRandomUsersByNumber(val)
.then((usersData) => (users.value = usersData));
});
因為 watch
是延遲載入,在 setup
階段不會呼叫回呼函式,若想要在 setup
階段呼叫,可加入 immediate: true
,在載入時便會先發出一次請求:
watch(searchInput, (val) => {
usersAPI
.getRandomUsersByNumber(val)
.then((usersData) => (users.value = usersData));
}, {immediate: true});
針對 composition API 的筆記先記錄到這邊,目前仍在學習中,如果內容有任何錯誤在煩請指出,謝謝您