Vue Props 和 Emit 完成子父組件的溝通

什麼是 Props?

Props 是用來從父組件向子組件傳遞資料的機制。這是一種單向數據流。

定義 Props

定義的方式有很多種,以下是各種你可能會看到的寫法,這些寫法就看個人或團隊喜歡哪一種

1
2
3
4
5
<script>
export default {
props: ['title', 'count']
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script>
export default {
props: {
title: {
type: String,
required: true // 必填
},
count: {
type: Number,
default: 0 // 預設值
}
}
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script>
export default {
props: {
count: {
type: Number,
required: true,
validator: function(value) {
// 限制 num 必須 >= 0
return value >= 0
}
}
}
};
</script>
1
2
3
4
5
6
7
8
9
10
<script>
export default {
props: {
count: {
type: [String, Number], // 可以是字串或數字
required: true
}
}
};
</script>
1
2
3
4
5
6
7
8
9
10
<script>
export default {
props: {
count: {
type: Number,
default: () => Math.floor(Math.random() * 100) // 隨機數字
}
}
};
</script>

在 Vue 3 中,可以使用 defineProps 來定義 props。以下是轉換為 Vue 3 的寫法:

1
2
3
<script setup>
const props = defineProps(['title', 'count']);
</script>
1
2
3
4
5
6
7
8
9
10
11
12
<script setup>
const props = defineProps({
title: {
type: String,
required: true // 必填
},
count: {
type: Number,
default: 0 // 預設值
}
});
</script>
1
2
3
4
5
6
7
8
9
10
11
12
<script setup>
const props = defineProps({
count: {
type: Number,
required: true,
validator: (value) => {
// 限制 count 必須 >= 0
return value >= 0;
}
}
});
</script>
1
2
3
4
5
6
7
8
<script setup>
const props = defineProps({
count: {
type: [String, Number], // 可以是字串或數字
required: true
}
});
</script>
1
2
3
4
5
6
7
8
<script setup>
const props = defineProps({
count: {
type: Number,
default: () => Math.floor(Math.random() * 100) // 隨機數字
}
});
</script>

使用 Props

在父組件中,你可以這樣使用子組件並傳遞 Props:

1
2
3
4
5
6
7
8
<template>
<div>
<my-component title="Hello World" :count="5"></my-component>

<!-- vue 3 有支援 v-model 寫法 -->
<!-- <my-component title="Hello World" v-model:count="5"></my-component> -->
</div>
</template>

什麼是 Emit?

Emit 是用來從子組件向父組件傳遞事件的機制。這允許子組件觸發父組件的回調函數。

使用 Emit

在子組件中,可以建立一個 emit 方法來發送事件,以下是一個簡單的更新數字範例:

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
// MyComponent.vue
<template>
<div>
<h3>{{ title }}</h3>
<p>目前數字:{{ count }}</p>
<button @click="incrementCount">增加</button>
</div>
</template>

<script>
export default {
props: {
title: {
type: String,
required: true,
},
count: {
type: Number,
default: 0,
}
},
methods: {
incrementCount() {
this.$emit('update-count', this.count + 1);
}
}
};
</script>
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
// MyComponent.vue
<template>
<div>
<h3>{{ title }}</h3>
<p>目前數字:{{ count }}</p>
<button type="button" @click="incrementCount">增加</button>
</div>
</template>

<script>
import { defineComponent } from 'vue'

export default defineComponent({
props: {
title: {
type: String,
required: true,
},
count: {
type: Number,
required: true,
},
},
emits: ['updateCount'],
setup(props, { emit }) {
const incrementCount = () => {
emit('updateCount', props.count + 1)
}

return {
incrementCount,
}
},
})
</script>
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
// MyComponent.vue
<template>
<div>
<h3>{{ title }}</h3>
<p>目前數字:{{ count }}</p>
<button @click="incrementCount">增加</button>
</div>
</template>

<script setup>
import { defineProps, defineEmits } from 'vue'

const props = defineProps({
title: {
type: String,
required: true,
},
count: {
type: Number,
default: 0,
},
})

const emit = defineEmits(['update-count'])

const incrementCount = () => emit('update-count', props.count + 1)
</script>

在父組件中,可以使用 v-on(或簡寫 @)來監聽這個事件,定義的方式為 @子元件方法=父元件方法 來實現父子元件的溝通方法,以下是父元件的範例:

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
// App.vue
<template>
<div>
<my-component
title="Hello World"
:count="count"
@update-count="updateCountHandler"
></my-component>
</div>
</template>

<script>
export default {
data() {
return {
count: 2,
};
},
methods: {
updateCountHandler(newCount) {
this.count = newCount; // 更新 count 的值
console.log('新的計數值:', newCount);
}
}
};
</script>
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
// App.vue
<template>
<div>
<my-component
title="Hello World"
:count="count"
@update-count="updateCountHandler"
></my-component>
</div>
</template>

<script>
import { ref } from 'vue'
import MyComponent from '@/components/MyComponent.vue'

export default {
components: {
MyComponent,
},
setup() {
const count = ref(2)

const updateCountHandler = newCount => {
count.value = newCount // 更新 count 的值
console.log('新的計數值:', newCount)
}

return {
count,
updateCountHandler,
}
},
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// App.vue
<template>
<div>
<my-component
title="Hello World"
:count="count"
@update-count="updateCountHandler"
></my-component>
</div>
</template>

<script setup>
import { ref } from 'vue'
import MyComponent from '@/components/MyComponent.vue'

const count = ref(2)

const updateCountHandler = newCount => {
count.value = newCount // 更新 count 的值
console.log('新的計數值:', newCount)
}
</script>

總結

  • Props 允許父組件向子組件傳遞資料,確保組件之間的數據流是單向的。
  • Emit 使子組件能夠向父組件發送事件,從而在父組件中執行特定的回調函數。