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 的值也會更新。