Vue.js 元件 – 自定義事件

父元件是使用 props 傳遞資料給子元件,但如果子元件要把資料傳遞回去,就需要使用自定義事件!

我們可以使用 v-on 繫結自定義事件, 每個 Vue 例項都實現了事件介面(Events interface),即:

  • 使用 $on(eventName) 監聽事件
  • 使用 $emit(eventName) 觸發事件

另外,父元件可以在使用子元件的地方直接用 v-on 來監聽子元件觸發的事件。

以下例項中子元件已經和它外部完全解耦了。它所做的只是觸發一個父元件關心的內部事件。

例項

<div id="app"> <div id="counter-event-example"> <p>{{ total }}</p> <button-counter v-on:increment="incrementTotal"></button-counter> <button-counter v-on:increment="incrementTotal"></button-counter> </div> </div> <script> Vue.component('button-counter', { template: '<button v-on:click="incrementHandler">{{ counter }}</button>', data: function () { return { counter: 0 } }, methods: { incrementHandler: function () { this.counter += 1 this.$emit('increment') } }, }) new Vue({ el: '#counter-event-example', data: { total: 0 }, methods: { incrementTotal: function () { this.total += 1 } } }) </script>

嘗試一下 ?

如果你想在某個元件的根元素上監聽一個原生事件。可以使用 .native 修飾 v-on 。例如:

<my-component v-on:click.native="doTheThing"></my-component>

data 必須是一個函式

上面例子中,可以看到 button-counter 元件中的 data 不是一個物件,而是一個函式:

data: function () {
  return {
    count: 0
  }
}

這樣的好處就是每個例項可以維護一份被返回物件的獨立的拷貝,如果 data 是一個物件則會影響到其他例項,如下所示:

例項

<div id="components-demo3" class="demo"> <button-counter2></button-counter2> <button-counter2></button-counter2> <button-counter2></button-counter2> </div> <script> var buttonCounter2Data = https://www.itread01.com/vue2/{ count: 0 } Vue.component('button-counter2', { /* data: function () { // data 選項是一個函式,元件不相互影響 return { count: 0 } }, */ data: function () { // data 選項是一個物件,會影響到其他例項 return buttonCounter2Data }, template: '<button v-on:click="count++">點選了 {{ count }} 次。</button>' }) new Vue({ el: '#components-demo3' }) </script>

嘗試一下 ?

自定義元件的 v-model

元件上的 v-model 預設會利用名為 value 的 prop 和名為 input 的事件。

<input v-model="parentData">

等價於:

<input 
    :value="https://www.itread01.com/vue2/parentData"
    @input="parentData = https://www.itread01.com/vue2/$event.target.value"
>

以下例項自定義元件 itread01-input,父元件的 num 的初始值是 100,更改子元件的值能實時更新父元件的 num:

例項

<div id="app"> <itread01-input v-model="num"></itread01-input> <p>輸入的數字為:{{num}}</p> </div> <script> Vue.component('itread01-input', { template: ` <p> <!-- 包含了名為 input 的事件 --> <input ref="input" :value="value" @input="$emit('input', $event.target.value)" > </p> `, props: ['value'], // 名為 value 的 prop }) new Vue({ el: '#app', data: { num: 100, } }) </script>

嘗試一下 ?

由於 v-model 預設傳的是 value,不是 checked,所以對於複選框或者單選框的元件時,我們需要使用 model 選項,model 選項可以指定當前的事件型別和傳入的 props。

例項

<div id="app"> <base-checkbox v-model="lovingVue"></base-checkbox> <div v-show="lovingVue"> 如果選擇框打勾我就會顯示。 </div> </div> <script> // 註冊 Vue.component('base-checkbox', { model: { prop: 'checked', event: 'change' // onchange 事件 }, props: { checked: Boolean }, template: ` <input type="checkbox" v-bind:checked="checked" v-on:change="$emit('change', $event.target.checked)" > ` }) // 建立根例項 new Vue({ el: '#app', data: { lovingVue: true } }) </script>

嘗試一下 ?

例項中 lovingVue 的值會傳給 checked 的 prop,同時當 <base-checkbox> 觸發 change 事件時, lovingVue 的值也會更新。