Vue3 基本用法

此篇是寫下關於 Vue3 Composition API 基本用法

定義資料

在 vue2 中定義資料總是在 data() 去宣告,而在 vue3 則不同,有 ref、reactive 的方式

Reactive

  • 宣告的值一定要是物件,不可是純值
  • 需使用 const,不可用 let,否則會失去雙向綁定

Ref

  • Vue 自行定義的屬性
  • 和 Reactive 相同,需使用 const,不可用 let,否則會失去雙向綁定
  • 宣告的值不限定任何型別,可以是純值

在實戰中 ref 會比 reactive 好用,且也是比較不會出錯的方式
不管是 ref、reactive 都要用 const 做宣告,才不會失去雙向綁定

Vue2 範例

傳統在 Vue2 方式宣告 num

1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<div>
{{ num }}
</div>
</template>

<script>
export default {
data: (() => {
num: 1
})
}
</script>

Vue3 範例

在 Vue3 則是要另外引入 ref 或 reactive,全部都在 setup() 裡完成,並在 return 時返回曾宣告的資料
讀取資料或設定資料都要加上 value,例如:num.valueperson.value

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
<template>
<div>
{{ num }}
{{ person }}
</div>
</template>

<script>
export default {
setup() {
const num = ref(1)
console.log(num.value)
num.value = 17

const person = ref({
name: 'Hazel'
})

return {
num,
person
}
}
}
</script>

props 接收及傳遞

在 Vue2 中,我們通常會用 props 接收來自父元件的參數

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
27
28
// 父元件
<template>
<children :text="text" />
</template>

<script>
export default {
text: '傳給子元件'
}
</script>

// 子元件
<template>
<div>
子元件
{{ text }}
</div>
</template>

export default {
props: {
text: {
type: String,
required: true,
default: ''
}
}
}

而在 Vue3,改為 setup寫法後,setup可接收 props 值、context 值

1
2
3
4
5
export default {
setup(props) {
console.log(props.text)
}
}

唯一要注意的是,props值不可直接寫成 ES6 解構,如果要使用解構 prop,必須用 toRefs

1
2
3
4
5
6
import { toRefs } from 'vuex

setup(props) {
const { text } = toRefs(props)
console.log(text.value)
}

使用 emit

子元件呼叫父元件事件,都會使用到 emit

Vue2 範例

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
27
28
29
<template>
<div>
子元件
<button @click="emit('emitToParent', 123)">
範例emit按鈕
</button>
</div>
</template>

<template>
// 父元件
<div>
<children @emitToParent="emitToParent" />
</div>
</template>

<script>
// 父元件
export default {
components: {
children
},
methods: {
emitToParent(value) {
console.log('父層接收到子層資料', value)
}
}
}
</script>

Vue3 範例

在 setup 引入 context.emit,也可以用解構 { emit }來使用 emit
setup 接收兩個參數,第一個參數是 props,第二個參數則是 context

子元件範例:

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<template>
<div>
子元件
<button @click="emitToParent">
範例emit按鈕
</button>
</div>
</template>

<template>
<div>
父元件
<children @emitToParent="getData" />
</div>
</template>

<script>
// 子元件
export default {
setup(props, { emit }) {
console.log(emit)

function emitToParent() {
emit('emitToParent', '子元件 -> 父元件資料')
}
}
}
// 父元件
export default {
components: { children },
setup() {
function getData(text) {
console.log(text) // 子元件 -> 父元件資料
}

return {
getData
}
}
}
</script>

$ref 取得 DOM 物件

在 Vue2 中呼叫 DOM 物件用法

  • 設定:<button ref="btn" />
  • 讀取:this.$refs['btn']

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <template>
    <button ref="btn">示範按鈕</button>
    </template>

    export default {
    mounted() {
    console.log(this.$refs.btn)
    }
    }

    而在 Vue3 則是改為以下寫法
    設定和 Vue2相同,一樣在 HTML 標籤上加入 ref=”btn”
    另外要引入 ref、onMounted,最後必須 return btn

  • 設定:<button ref="btn" />

  • 讀取:btn.value
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <template>
    <button ref="btn">示範按鈕</button>
    </template>
    // 宣告 ref, onMounted
    const { ref, onMounted } = Vue

    export default {
    setup() {
    const btn = ref(null) // undefined

    onMounted(() => {
    console.log(btn.value)
    })

    return {
    btn
    }
    }
    }

Provider、Inject 方法

跨元件層級的資料傳遞 Provider
假設是在最外層,可以運用 Provider 方法直接將資料傳到最內層
在父層使用 provide 傳出去,在子層用 inject 接收 inject: ['user']

傳遞

1
provide('user', user)

接收
1
inject('user')

Vue2 寫法

子層

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script>
const children = {
inject: ['user'],
template: `<div>
{{ user.name }}
{{ user.uuid }}
</div>`,

created() {
console.log(this.user)
this.user.name = 'Hazel'
}
}
</script>

最外層
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script>
export default {
components: { children },
data() {
return {
user: {
name: 'Ellie',
uuid: 1348560
}
}
},
provide() {
// provide function 也必須用 return
return {
user: this.user
}
}
}
</script>

Vue3 範例

children 子元件,引入 inject 來接收 user 參數
子元件使用,如果會改變 user 值時,會避免影響到父層,建議使用淺層或深層拷貝方式處理

1
2
3
4
5
6
7
8
9
10
11
const { inject } from Vue

export default {
setup(props) {
const person = inject('user')

return {
person
}
}
}

父元件引入 provide,傳遞 user 物件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const { ref, provide } = Vue

export default {
components: { children },
setup() {
const user = ref({
name: 'Ellie',
uuid: 1348560
})

// 自定義名稱,要發送的資料內容
provide('user', user)

return {
user
}
}
}

Watch

引入 watch,在 setup 設定 watch function

基本用法

1
2
3
4
5
6
7
8
9
const { watch } = Vue
export default {
setup() {
watch(監聽的變數, (newValue, oldValue) => {
...
})
}
}

深層監聽

深層監聽物件屬性,加上 deep: true

1
2
3
4
5
6
watch(() => watchObject.value.skill, (newVal, oldVal) => {
console.log(newVal, oldVal)
})
watch(watchObject, (newVal, oldVal) => {
console.log(newVal, oldVal)
}, { deep: true })

多值監聽

需要監聽多個變數,可以用陣列監聽。但如果在同一個 function 裡同時改變這些監聽來源,watch 只會執行一次

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const firstName = ref('')
const lastName = ref('')

watch([firstName, lastName], (newValues, preValues) => {
console.log(newValues, preValues)
})
// 若監聽是深度嵌套对象或数组中的屬性改變,要加上 deep
watch([firstName, lastName], (newValues, preValues) => {
console.log(newValues, preValues)
},
{ deep: true }
)

firstName.value = 'Hazel' // Logs: ['Hazel', ''] ['', '']
lastName.value = 'Wu' // Logs: ['Hazel', 'Wu'] ['Hazel', '']

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
27
28
29
30
31
32
const { ref, watch } = Vue
export default {
setup(props) {

// 文字
const name = ref('Hazel')

watch(name, (newValue, oldValue) => {
console.log(`新:${newValue},舊:${oldValue}`)
})

// 物件
const watchObject = ref({
name: 'Hazel',
skill: [
'js',
'vue',
'nodejs'
]
})

// 物件深層監聽,需要加上箭頭函示
watch(() => watchObject.value.skill, (newValue, oldValue) => {
console.log(`新:${newValue},舊:${oldValue}`)
})

return {
name,
watchObject
}
}
}

WatchEffect

WatchEffect 是 Vue3 獨有的,和 Watch 有些不同

WatchEffect

  1. 使用上較隨性,不需要指定需要監聽的變數。但 Watch 需要指定監聽哪個變數
  2. WatchEffect 可以被停止,但 Watch 不能
  3. WatchEffect 無法取得前一個值,但 Watch 可以取得被修改前的值

基本用法

1
2
3
4
5
6
7
8
9
10
11
12
13
import { watchEffect } from Vue

export default {
setup() {
const num = ref(0)
const name = ref('Hazel')

watchEffect(() => {
console.log(num)
console.log(name)
})
}
}

WatchEffect 停止

宣告變數 stopWatchEffect 並執行 watchEffect function
只要執行 stopWatchEffect 監聽便會停止

1
2
3
4
5
6
const stopWatchEffect = watchEffect(() => {
num.value++
console.log(num)

if (num.value === 5) stopWatchEffect()
})


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!