自定義事件有能力使子組件事件觸發父組件中的動做。
那麼父組件如何監聽事件呢?可使用指令v-on:event-name="callback"
監聽。
而子組件又是如何觸發事件的呢? 很簡單,調用this.$emit(eventName)
。
先來個簡單例子javascript
new Vue({ el:'#app-1', methods:{ callback:function(){ alert('父組件監聽到事件觸發,執行回調。') } }, components: { "component-1":{ template:'<button v-on:click="emitor" class="btn btn-info">\ 子組件模板:點擊觸發自定義事件</button>', methods:{ emitor:function(){ console.log('111') this.$emit('alert-event') } } } } })
<div id="app-1"> <component-1 v-on:alert-event="callback"></component-1> </div>
根據以上代碼,能夠得出個事件執行流程,基本上無論什麼自定義事件都是這個流程java
this.$emit('event')
v-on
監聽event
methods
中的callback
子組件已經和它外部徹底解耦了。它所作的只是報告本身的內部事件,由於父組件可能會關心這些事件。
在事件執行的同時,子組件還能夠在觸發事件的同時掛上一些負載的數據,隨着事件傳遞給父組件。
使用API的第二個參數this.$emit(event, payload)
,具體以下。app
new Vue({ el: '#app-2', data: { message: '' }, methods: { handleMessage: function (payload) { this.message = payload.message } }, components: { "component-2": { data: function () { return { message: '' } }, template: '\ <div>\ <input type="text" v-model="message" class="form-control w-25 mt-2">\ <button @click="sendMsg" class="btn btn-info mt-2">發送</button>\ </div>', methods: { sendMsg: function () { this.$emit('message', { message: this.message }) } } } } })
<div id="app-2"> <input v-model="message" class="form-control w-25"> <component-2 @message="handleMessage"></component-2> </div>
點擊發送按鈕觸發事件並把信息傳遞給父組件,能夠看到仍是這裏一樣遵循自定義事件流程,其餘都是煙霧,之多了個負載this.$emit('message', { message: this.message })
this
經過.native
後綴還能夠在子組件元素根節點上綁定原生事件的監聽。spa
new Vue({ el:'#app-3', methods:{ todo:function(){ alert('事件回調方法是父組件中的') } }, components:{ "component-3":{ template:'<button class="btn btn-info mt-2">原生事件監聽</button>' } } })
<div id="app-3"> <component-3 @click.native="todo"></component-3> </div>
仍是要千萬注意,回調方法在父組件做用域上。雙向綁定
能夠經過如下步驟實現一個雙向綁定:code
v-bind:prop.sync="foo"
進行數據下發,這裏以.sync
修飾符標註,通知父組件子組件須要進行props
的更新。this.$emit("update:prop",newValue)
通知父組件本身須要把prop
更新爲一個新值newValue
(以子組件的data
選項做爲過渡變量)newValue
,更新foo
的數據,並把新數據從新下發給子組件的prop
注意:這裏並非子組件props
值的改變引起父組件數據的改變,而是利用子組件的data
作橋樑,經過事件及其負載引發父組件的變更。
new Vue({ el: '#app-4', data: { parentMsg: 'parent\'s message' }, components: { "component-4": { props: ['child_msg'], data: function () { return { inputText: this.child_msg } }, template: '\ <div>\ <input v-model="inputText" class="form-control form-control-sm w-25" type="text">\ </div>', watch: { child_msg: function (val) { this.inputText = val }, inputText: function (val) { this.$emit('update:child_msg', val) } } } } })
<div id="app-4"> <input v-model="parentMsg" class="form-control form-control-sm w-25" type="text"> <component-4 :child_msg.sync="parentMsg" class="mt-2"></component-4> </div>
父、子組件各包含一個輸入框,而且將它們綁定到本身的某data
屬性上。watch
子組件的該data
屬性,一有輸入就觸發事件通知父組件,並payload
新值。父組件經過payload
更新本身的data
,並經過prop
將新值下發給子組件,子組件watch
本身的prop
,prop
一旦變更,將新變更賦給data
。component
咱們在用輸入框時,會用v-model
進行雙向綁定。orm
<input v-mode="message">
等價於<input :value="message" @input="message = $event.target.value" />
事件
具體行爲:① 在input
的value
屬性上引用組件的data
② 發生oninput
事件時,更新組件data
,從而更新value
。
new Vue({ el:'#app-6', data:{ message:"Hello" } })
<div id="app-6"> <input v-model="message"/> <input :value="message" @input="message = $event.target.value" /> <div>{{message}}</div> </div>
前提:
<myComponent v-model="price">
等價於
<myComponent :value="price" @input="price = arguments[0]" >
new Vue({ el: '#app-7', data: { price: 100 }, components: { "component-7": { props: ['value'], template: '\ <div>\ <input :value="value" @input="updateValue($event.target.value)" class="form-control form-control-sm w-25">\ <slot></slot>\ <div><span class="badge badge-info">子組件Prop:【{{value}}】</span></div>\ </div>', methods:{ updateValue:function(value){ value = value+"-" this.$emit('input',value) } } } }, })
<div id="app-7"> <!-- <component-7 v-model="price"></component-7> --> <component-7 :value="price" @input="price = arguments[0]" > <div> <span class="badge badge-info">父組件數據:【{{price}}】</span> </div> </component-7> </div>
這裏的流程,輸入框輸入時,觸發子組件上input
事件並執行updateValue
方法,方法參數爲輸入框中的value
(經過$emit.target.value
獲取),方法能夠先對value
進行一系列加工處理造成super_value
,最後使用this.$emit('input',super_value)
觸發父組件在子組件節點上監聽的input
事件,並將加工過的super_value
負載在事件上。父組件@input="price = arguments[0]"
中的arguments[0]
便是這個super_value
,父組件經過input
的回調更新本身的data
,在將data
下發給子組件的value
特性。
這裏若是使用v-model
指令,那麼子組件特性value
、父組件監聽的事件input
及其回調price = arguments[0]
, 這些都是固定的,不能變化。
此示例的執行流程其實與雙向綁定(.sync修飾符與update事件)中的例子是同樣的。
只是這裏父組件上的input
事件功效沒有雙向綁定中update
事件那麼強大。
在輸入框組件中已經說過v-model
的種種限制,其中最主要的兩點,下發的組件特性必須命名爲value
和父組件監聽的只能綁定事件input
,不靈活, 例如在checkbox
中,我要給下發的特性取名爲checked
代替value
,而且父組件不想監聽@input
事件,而是@change
事件。
爲了解決這個不靈活的問題,能夠在組件model
選項設置prop
和event
,以下
new Vue({ el: '#app-9', data: { isChecked: false, message:'please choose this box' }, components: { 'component-9': { model: { prop: 'checked', event: 'change' }, props:{ checked:Boolean, value:String }, template: '<div><input type="checkbox" @click="choose($event.target.checked)"><slot></slot></div>', methods:{ choose:function(checked){ this.$emit('change',checked) } } } } })
<div id="app-9" style="height:500px"> <component-9 v-model="isChecked" v-bind:value="message"> <span class="badge badge-info">特性`value`如今從v-model綁定中解放出來了,可自定義使用</span> </component-9> </div>