一、Why Composition API?
創建Vue組件使我們能夠將接口的可重復部分及其功能提取到可重用的代碼段中。就可維護性和靈活性而言,僅此一項就可以使我們的應用程序發展得很遠。但是,我們的集體經驗證明,僅憑這一項可能還不夠,尤其是當您的應用程序變得非常大時-考慮數百個組件。當處理如此大的應用程序時,共享和重用代碼變得尤為重要。
二、Options API
1. 設計動機
- 包含一個描述組件選項 ( data, methods, props 等) 的對象
- Options APi 開發復雜組件,同一個功能邏輯的代碼被拆分到不同選項
2. Options Demo

三、Composition API
1. 設計動機
- Vue.js 3.0 新增的一組 API
- 一組基於函數的 API
- 可以更靈活的組織組件的邏輯
2. Composition API Demo

四、Options API VS Composition API
1. 入口對比
Vue2.x: 每個 Vue 應用都是通過用 Vue 函數創建一個新的 Vue 實例開始的:
var vm = new Vue({
// 選項
})
Vue3.x: Vue.js的核心是一個系統,通過 createApp 創建系統,並通過 mount 綁定首頁,該系統使我們能夠使用簡單的模板語法聲明性地將數據呈現到DOM:
Vue.createApp({}).mount('#counter')
2. 方法 對比
Vue 2.x : data, methods, props, mounted, components, computed, watch 等
Vue3.x : setup, reactive, onMounted, onUnmounted, toRefs, Ref, computed,watch,watchEffect 等
3. 生命周期鈎子-對比
Vue2.x 生命周期圖示
Vue3.x 生命周期掛鈎
4. Demo 對比

5. 邏輯模塊拆分
Vue2.x: 不具備
Vue3.x: 通過setup 將邏輯拆分
6. 舉例說明 邏輯拆分
查看以下代碼,我們會看到,我們可以將一個邏輯通過函數的形式進行包裹,分邏輯拆分,每個邏輯部分互相獨立,不受影響,其中每個函數都可使用生命周期鈎子進行組合,因為函數可以以方法的形式去重用和共享
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
x: {{ x }} <br>
y: {{ y }}
</div>
<script type="module">
import { createApp, onMounted, onUnmounted, reactive, toRefs, ref, computed, watch, watchEffect } from './node_modules/vue/dist/vue.esm-browser.js'
/** reactive */
function useMousePosition() {
// 第一個參數 props
// 第二個參數 context,attrs、emit、slots
const position = reactive({
x: 0,
y: 0
})
const update = e => {
position.x = e.pageX
position.y = e.pageY
}
onMounted(() => {
window.addEventListener('mousemove', update)
})
onUnmounted(() => {
window.removeEventListener('mousemove', update)
})
return toRefs(position)
}
/** ref */
function useCount() {
const count = ref(0)
return {
count,
increase: () => {
count.value++
}
}
}
/** computed */
function todosFun() {
const todos = reactive(data)
const activeCount = computed(() => {
return todos.filter(item => !item.completed).length
})
return {
activeCount,
push: () => {
todos.push({
text: '開會',
completed: false
})
}
}
}
/** watch */
function answerFun(params) {
const question = ref('')
const answer = ref('')
watch(question, async (newValue, oldValue) => {
const response = await fetch('https://www.yesno.wtf/api')
const data = await response.json()
answer.value = data.answer
})
return {
question,
answer
}
}
/** watchEffect */
function countFun(params) {
const counts = ref(0)
const stops = watchEffect(() => {
console.log(count.value)
})
return {
counts,
stops,
increases: () => {
count.value++
}
}
}
const app = createApp({
setup() {
const { x, y } = useMousePosition()
return {
x,
y,
...useCount(),
...todosFun(),
...answerFun(),
...countFun()
}
}
})
app.mount('#app')
</script>
</body>
</html>
五、參考文獻
2. Vue2 生命周期
4. Vue 3 生命周期
