人類溝通需要技巧,程式語言靠的是方法。
我們除了可以透過 Props 來讓父元件傳值給子元件外,也可以透過子元件向父元件傳遞訊息,並可以直接在子元件中操控父元件裡的資料。
在父元件傳值給子元件所使用的 Props ,在傳遞資料時是單向資料流(One-Way Data Flow),也就是說,只允許子元件向父元件傳遞資料,而不允許子元件直接操控 Props 裡的資料。有這個原則的原因是因為如果直接讓子元件直接操控 Props 裡的資料,資料的控制邏輯會變的很複雜與雜亂。單向資料流還是比較容易理解,Vue 也較推薦單向資料流的用法。雖然可以做到雙向但 Vue 不建議使用雙向。
那麼在 Vue 如何透過自定義事件向父元件傳遞訊息呢?即是使用 Vue 的內建$emit()
方法。
子元件透過自定義事件向父元件傳遞訊息
語法:<button v-on:click="$emit('enlarge-text')>Enlarge Text</button>
說明:一個子元件裡的按鈕,點擊時會觸發一個特定的方法$emit()
,並帶上一個參數,此參數為自定義的事件名稱enlarge-text
,這個事件會傳遞給父元件,所以父元件會去監聽這個事件。
父元件中監聽子元件的事件
語法:<menu-item v-on:enlarge-text="fontSize += 0.1"></menu-item>
說明:v-on:enlarge-text
為綁定事件名稱,fontSize += 0.1
則為事件對應的處理邏輯。
透過實作的情境會比較清楚傳遞的運作原理:
實作範例效果:在子元件中點擊Enlarge Text
按鈕之後,會控制父元件中的parentsMsg
使文字有大小變化。
template
插入我們在data
的屬性parentsMsg
內容為'Hello, is parentsMsg'
,為控制目標。template
裡加上按鈕綁定監聽事件,並以$emit()
方法,帶上指定的自定義事件參數。template
綁定剛剛的自定義事件參數methods
增加方法handleSize
,每按一次按鈕增加字體大小 5px,並在 data 裡增加屬性fontSize: 12,
預設值。template
的插入值parentsMsg
元素上綁定元素的字體大小,記得要加入字體單位px
<!-- 父元件的HTML -->
<div id="app">
<menu-item @enlarge-text="handleBiggerSize"></menu-item>
</div>
<script>
// 子元件 使用$emit()傳遞
Vue.component('menu-item',{
template: `
<div>
<div >{{parentsMsg}}</div>
<button @click="$emit('enlarge-text')">放大父元件中元素的字體大小</button>
</div>
`
})
// 父元件
const vm= new Vue({
el:'#app',
data:{
parentsMsg: 'Hello, is parentsMsg',
fontSize: 16,
},
methods:{
handleBiggerSize: function(){
// 字體變大
this.fontSize += 5
},
}
})
</script>
我們也可以直接在$emit()
裡以第二個參數帶值進去,就不需要每次去父元件的方法裡修改。
子元件透過自定義事件向父元件傳遞訊息+帶值
語法:<button v-on:click="$emit('enlarge-text',0.1)>Enlarge Text</button>
說明:一個子元件裡的按鈕,點擊時會觸發一個特定的方法$emit()
,並帶上兩個參數,第一參數為自定義的事件名稱enlarge-text
,第二參數是值,個事件和值會直接傳給父元件,所以父元件會去監聽這個事件。
父元件中監聽子元件的事件
接收語法:<menu-item v-on:enlarge-text+= $event"></menu-item>
說明:v-on:enlarge-text
為綁定事件名稱,fontSize += $event
則為事件對應的處理邏輯會對應到子主件的綁定方法的第二參數值,$event
是固定的寫法。
當按下子元件的模版template
裡的按鈕,會直接取到第二參數作為放大字體的增加單位。
實作範例效果:
<!-- 父元件的HTML -->
<div id="app">
<menu-item @minify-text="handleMinifySize($event)"></menu-item>
</div>
<script>
// 子元件 使用$emit()傳遞
Vue.component('menu-item',{
template: `
<div>
<div >{{parentsMsg}}</div>
<button @click="$emit('minify-text',5)">縮小父元件中元素的字體大小</button>
</div>
`
})
// 父元件
const vm= new Vue({
el:'#app',
data:{
parentsMsg: 'Hello, is parentsMsg',
fontSize: 16,
},
methods:{
handleMinifySize: function(value){
// 字體變大
this.fontSize -= value
}
}
})
</script>
每日一句法文有益身心:Je suis fatigué ! --> 者.雖.發踢給! --> 我好累啊!