📢 本文由 gemini-2.5-flash 翻譯
建立專案
需要 Node.js 16.0 或更高版本,請執行指令
這指令將會安裝並執行 create-vue
setup
執行週期
執行時機比 beforeCreate() 還要早,所以也無法使用 this
1
2
3
4
5
6
7
8
9
10
| <script>
export default{
setup(){
console.log('setup', this)
},
beforeCreate(){
console.log('beforeCreate')
}
}
</script>
|
執行後,會先印出 setup undefined 然後才是 beforeCreate
資料呼叫
如果想在 <template> 中使用 setup() 函式裡定義的資料或函式,就必須要 return
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| <script>
export default{
setup(){
// data
const msg = 'hello vue3'
// function
const logMsg = () => {
console.log(msg)
}
// return
return{
msg,
logMsg
}
}
}
</script>
|
只有 return 之後,才能在 <template> 裡使用
1
2
3
4
| <template>
<div>{{ msg }}</div>
<button @click="logMsg">button</button>
</template>
|
語法糖
每次都要 return 確實很麻煩,實際上可以直接透過在 <script> 標籤加上 setup,這樣就可以自動 return,上述範例就可以改寫為
1
2
3
4
5
6
| <script setup>
const msg = 'hello vue3'
const logMsg = () => {
console.log(msg)
}
</script>
|
當然,實際上還是會 return,只是不用手動寫出來了
響應式資料
reactive
reactive() 函式接收一個物件型態的資料,並回傳一個響應式的物件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| <script setup>
import { reactive } from 'vue'
const state = reactive({
count: 100
})
const addCount = () => {
state.count++
}
</script>
<template>
<div>
<div>{{ state.count }}</div>
<button @click="addCount">+1</button>
</div>
</template>
|
ref
ref() 接收簡單型別或複雜型別的資料,並回傳一個響應式物件。其本質是在原有傳入資料的基礎上,在外層包裝了一個物件,使其變成更複雜的型別。其實也是透過 reactive() 實現響應式的
所以,在 <script> 中存取資料時,需要透過 .value。而在 <template> 中存取資料則直接使用變數即可。上述範例使用 ref() 重寫如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| <script setup>
import { ref } from 'vue'
const c = ref(0)
const addC = () => {
c.value++
}
</script>
<template>
<div>
<div>{{ c }}</div>
<button @click="addC">+1</button>
</div>
</template>
|
實際開發中,只使用 ref() 會比較彈性且統一
computed
計算屬性 computed() 與 Vue2 類似,只是變成可以任意呼叫的函式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| <script setup>
import { computed, ref } from 'vue'
const list = ref([1, 2, 3, 4, 5, 6, 7, 8])
const computedList = computed(() => {
return list.value.filter(item => item > 2)
})
</script>
<template>
<div>{{ list }}</div>
<div>{{ computedList }}</div>
</template>
|
這樣建立出來的屬性是唯讀的,不是可寫的。若需要可寫,需要明確宣告 get() 與 set(),以下擷取自官方範例
1
2
3
4
5
6
7
8
9
10
11
12
| <script>
const count = ref(1)
const plusOne = computed({
get: () => count.value + 1,
set: (val) => {
count.value = val - 1
}
})
plusOne.value = 1
console.log(count.value) // 0
</script>
|
擷取自:
https://cn.vuejs.org/api/reactivity-core.html#computed
watch
watch() 函式同樣是監聽一個或多個資料的變化,當資料變化時執行回呼函式。不過多了兩個額外參數 immediate 和 deep
1
2
3
| watch(count, (newValue, oldValue) => {
console.log('count changed', oldValue, newValue)
})
|
1
2
3
| watch([count, name], ([newCount, newName], [oldCount. oldName]) => {
console.log('count or name has changed', [newCount, newName], [oldCount. oldName])
})
|
範例,這裡我使用了簡化的 pug,不過其實也很好懂啦
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| <script setup>
import { ref, watch } from 'vue'
const count = ref(0)
const name = ref('John')
const addCount = () => count.value++
const changeName = () => name.value = 'Mike'
// 監聽單一資料的變化
watch(count, (newValue, oldValue) =>{
console.log('count changed', oldValue, newValue)
})
// 監聽多個資料的變化
watch([count, name], (newArr, oldArr) => {
console.log('count or name changed', oldArr, newArr)
})
</script>
<template lang="pug">
div count: {{ count }}
button(@click="addCount") +1
div name: {{ name }}
button(@click="changeName") change name
</template>
|
immediate 表示立即執行,即在進入頁面後會立即執行一次,此時的 oldValue 會是 undefined
1
2
3
4
5
| watch(count, (newValue, oldValue) =>{
console.log('count changed', oldValue, newValue)
}, {
immediate: true
})
|
deep
deep 是深度監聽,因為預設 watch 進行淺層監聽是無法監聽到複雜型別的變化的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| <script setup>
import { ref, watch } from 'vue'
const userInfo = ref({
name: 'John',
age: 18
})
const changeUserInfo = () => {
userInfo.value.age++
}
watch(userInfo, (newValue) => {
console.log('userInfo changed', newValue)
}, {
deep: true
})
</script>
<template lang="pug">
div {{ userInfo }}
button(@click="changeUserInfo") change userInfo
</template>
|
複雜型別單一屬性監聽
使用 deep 將會對複雜型別的所有屬性進行監聽,也就是只要任一屬性發生變化,都會執行函式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| <script setup>
import { ref, watch } from 'vue'
const userInfo = ref({
name: 'John',
age: 18
})
const changeAge = () => {
userInfo.value.age++
}
const changeName = () => {
userInfo.value.name = 'Mike'
}
watch(() => userInfo.value.age, (newValue, oldValue) => {
console.log('age changed', oldValue, newValue)
})
</script>
<template lang="pug">
div {{ userInfo }}
button(@click="changeAge") change age
button(@click="changeName") change name
</template>
|
這樣就只有 age 改變時才會觸發,且回傳值是 age 的值
生命週期
Vue3 的生命週期比較
| Option API | Composition API |
|---|
| beforeCreate/created | setup |
| beforeMount | onBeforeMount |
| mounted | onMounted |
| beforeUpdate | onBeforeUpdate |
| updated | onUpdated |
| beforeUnmount | onBeforeUnmount |
| unmounted | onUnmounted |
與組合式 API 的不同就是變成函式呼叫,而且可以呼叫多次
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| <script setup>
import { onMounted } from 'vue';
// 組合式的 beforeCreate 和 created 直接撰寫
const getList = () => {
console.log('從後端取得資料')
}
// 執行,進入頁面便請求
getList()
// 生命週期函式可以呼叫多次,會按照順序執行
onMounted(() => {
console.log('邏輯一')
})
onMounted(() => {
console.log('邏輯二')
})
</script>
|