Vuejs
當父組件需要接收子組件訊息、數據時,可以透過在子組件 自定義事件
達成,除此之外若是需要監聽子組件 根元素 原生事件,可以透過 v-on
配合 .native
修飾符監聽:
.native
監聽子組件根元素的 原生事件
今天創建一個 my-component
子組件,父組件對 v-on
添加 .native
後可監聽子組件根元素原生事件。
下方簡單範例監聽子組件根元素 click
事件,父組件一旦監聽到該事件,便更改數據
Vue.component('my-component', {
template: `<div>這是子組件
<button>BUTTON</button>
</div>`
})
const vm = new Vue({
el: '#app',
data: {
text: '原始值'
},
template: `
<div class="app">
<p>父組件數據: {{ text }}</p>
<my-component @click.native="handler"/>
</div>`,
methods: {
handler(event) {
this.text = '修改了'
console.log('event.target', event.target)
console.log('event.currentTarget', event.currentTarget)
},
},
})
該 根元素 不必要
為事件物件被指派到的 Event target 元素,例如今天的 click
事件的 Event target
為 button
,但事件流 ^規範定義^ 通過了根元素,事件仍然會被監聽,就如同原生 DOM 事件一樣。
$listeners
在子組件特定元素上監聽原生事件除了在子組件中監聽 根元素
原生事件,也可以透過 $listeners
物件,將父組件的所有事件監聽器指向子組件的特定元素。
唯讀類型的物件,是一個包含了 parent-scope
所有事件監聽器的物件。
透過 created
階段,打印 $listeners
,可以看見如下方的物件,裡面包涵 parent-scope
的所有事件監聽器。
Vue.component('my-component', {
template: `<div>
<label for="name" >name: <input type="text" id="name"></label>
</div>`,
created() {
console.log(this.$listeners)
},
})
父組件於子組件對 focus
、click
兩事件進行監聽,對應 $listeners
中的兩個事件監聽器。
const vm = new Vue({
el: '#app',
template: `
<div class="app">
<my-component @focus="handler('focus')" @click="handler('click')"
/>
</div>`,
methods: {
handler(event) {
console.log(event)
},
},
})
今天若是要在子組件特定元素上監聽原生事件,變使用 v-on="$listener"
監聽子組件元素。
Vue.component('my-component', {
template: `<div>
<label for="name" >name: <input type="text" id="name"></label>
</div>`
})
const vm = new Vue({
el: '#app',
template: `
<div class="app">
<my-component @focus="handler('focus')" @click="handler('click')"
/>
</div>`,
methods: {
handler(event) {
console.log(event)
},
},
})
單純使用 .native
監聽根元素,無法監聽 focus
事件,由於 focus
不會 bubble
,所以對 label
監聽 focus
無效,在此若是要將父組件的 focus
事件監聽器指向子組件的特定元素,可以改採 $listeners
:
對子組件添加 v-on="$listeners"
<label for="name" >name: <input type="text" id="name" v-on="$listeners"></label>
相當於:
<label for="name" >name: <input type="text" id="name" v-on="{click: function(){...}, focus: function(){...}
}"></label>
並且移除父組件上的 .native
,由於 $listeners
不包含使用 .native
的事件監聽器。
此時子組件的 input
元素便會開始監聽 focus
、click
原生事件。
This event type is similar to focusin
, but is dispatched after focus is shifted, and does not bubble.
focus
事件沒有 bubble
,於是上述範例情境下針對 label
監聽 focus
沒有作用。
今天提及 $listeners
物件,該物件包含 parent-scope
中的事件監聽器,透過該物件,我們可以靈活地在子組件特定元素上監聽原生事件。
若是文中有任何錯誤、錯字、想討論的內容,歡迎各位大大不吝鞭笞指正、交流分享,筆者不慎感激 ✦ ✦ ✦
▶︎ 筆者 github:https://github.com/YUN-RU-TSENG
▶︎ 老王賣瓜之筆者另一篇鐵人:每天來點 CSS Specification
▶︎ 倘若不斷向深處扎根,似乎就能茁壯成長 - RM