Table of contents
元件的溝通傳遞
Vue.js 每個元件的實體狀態、模板等作用範圍都應該要是獨立的, 也就是我們不能(也不應該)在子元件的模組「直接」去修改父元件,甚至是另一個元件的資料,因為元件化就是為了能夠重複使用,希望這些元件可以根據『外部&內部』資料的改變,來呈現出不同的結果,
- 如果需要透過父層來傳遞資料給子層的話,就是
props
- 如果需要透過子層來傳遞資料給父層的話,就是
emit
![props&emit 傳遞流程](d1dwq032kyr03c.cloudfront.net/upload/images.. "props&emit 傳遞流程")
Props(父層傳遞資料給子層)
![props 傳遞流程](book.vue.tw/assets/img/2-2-props-01.e62d8c8.. "props 傳遞流程")
實作範例為:將 App.vue
當作父層,製作元件 propsTest.vue
當作子層:
- 父層:
- 新增
msg
變數 - 使用
v-bind
將 msg 傳入子層元件,:innerMsg(子層接收 msg 的變數名稱)="msg"
- 新增
- 子層:
- 新增 props 設定,新增父層的自定義接收資料的變數
innerMsg
- 使用 setup(props) 的方式,將 props return 出來
- 在子層 template 內,透過 props.proxy 的方式將資料取出
- 新增 props 設定,新增父層的自定義接收資料的變數
parent-component:
<script setup>
import { ref } from 'vue';
// 新增 msg 變數
const msg = ref('')
</script>
<template>
<div class="wrapper">
<!-- propsTest component -->
<!-- 使用 v-bind:子層接收資料的名稱=msg -->
<PropsTest :innerMsg="msg" />
<PropsTest />
</div>
</template>
child-component:
<script>
export default {
props: {
innerMsg: {
type: String,
default: "Michael"
}
},
setup(props) {
return { props }
}
}
</script>
<template>
<!-- 從 props.proxy 去拿取內裡所需要的資料 -->
<h1>{{ props.innerMsg }}</h1>
</template>
除錯處理
為了防止 props 傳入的資料型別與預期不同,以及遺漏傳入 props 資料的錯誤產生, 最好是用此方式來建立 props 設定,
- 新增 type 設定 確保傳入的型別有符合預期,如果傳入錯誤型別,瀏覽器會在 devtool 產生 warning 警告提示來讓我們知道,不會直接爆出錯誤
- 新增 default 設定 當沒有傳入變數時,則會顯示出 default 的數值,而不會爆出沒有傳入變數的錯誤
<script>
export default {
props: {
innerMsg: {
type: String,
default: "Michael"
}
},
setup(props) {
return { props }
}
}
</script>
如果型別為 Array, Object, Function 寫法上會有些微差異,下方列出這三項的寫法差異:
<script>
export default {
props: {
innerMsg: {
type: String,
default: "沒有數值傳入",
},
arr: {
type: Array,
default: () => []
},
obj: {
type: Object,
// default: () => {
// return {
// }
// },
// 上方可以簡寫成下方這樣
default: () => ({}),
},
func: {
type: Function,
default: () => { },
}
},
setup(props) {
return { props }
},
}
</script>
emit(子層往父層傳遞)
Vue2 的方法是使用 this.$emit("emitTest","Michael")
,
使用 this 的方式來將數值回傳給父層,但由於 composition API 是沒有 this 的,取而代之現在是使用 context 的方式來回傳 emit 數值給父層。
emit 有兩種使用方式:
傳入 context ,並且使用
context.emit
以及 return contextsetup(props, context) { const emitNum = ref(0) onMounted(() => { // console.log(context.emit); context.emit('Emit', emitNum.value) }) return { emitNum, context } }
使用解構方式來使用 emit,寫起來會比範例 1 簡短許多
setup(props, { emit }) { const emitNum = ref(0) onMounted(() => { // console.log(context.emit); emit('emitTest', emitNum.value) }) return { emitNum } }
:::warning 而 props 如果沒有需要用到,是可以不用回傳出來的,但一定得放入 setup 裡頭,才有辦法使用 context 去使用 emit 回傳數值到父層。 :::
App.vue:
@子層定義的第一個參數名稱="父層方法"
<script setup>
import Emit from './components/Emit.vue';
const handleEmit = (e) => {
console.log(e);
}
</script>
<template>
<Emit @emitTest="handleEmit" />
</template>