vue中元件間的通訊
元件間的關係可分為父子元件通訊、兄弟元件通訊、跨級元件通訊。
子元件向父元件傳遞資料
自定義事件:
使用 $on()和 $emit()來實現通訊
v-on除了監聽DOM事件外,還可以用於元件之間的自定義事件。
子元件用 $emit()來觸發事件,父元件用 $on()來監聽子元件的事件。 $emit()方法的第一個引數是自定義事件的名稱,後面的引數是要傳遞的資料,可以不寫,或者寫多個。
父元件也可以直接在子元件的自定義標籤上使用v-on來監聽子元件觸發的自定義事件。
例:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <script src="https://cdn.jsdelivr.net/npm/
[email protected]/dist/vue.js"></script> </head> <body > <div id="app"> <p>總數:{{ total }} </p> <my-component @increase="handleGetTotal" @reduce="handleGetTotal"></my-component> </div> </body> <script> Vue.component('my-component', { template: ` <div> <button @click="handleIncrease">+1</button> <button @click="handleReduce">-1</button> </div> `, data:function ( ) { return { counter:0 } }, methods:{ handleIncrease:function(){ this.counter++; this.$emit('increase',this.counter); }, handleReduce:function(){ this.counter--; this.$emit('reduce',this.counter); } } }); var app=new Vue({ el:'#app', data:{ total:0 }, methods:{ handleGetTotal:function(total){ this.total=total; } } }) </script> </html>
示例中,以點選+1按鈕為例,子元件的+1按鈕點選後,觸發handleIncrease事件。而在子元件內的methods中,handleIncrease事件內使用$emit()觸發了increase事件,並且將此時的counter傳入increase這個事件內,父元件用v-on:increase監聽該自定義事件。在例項的方法中handleGetTotal()函式接收到由子元件傳遞過來的total,並將total賦值給例項中data的total。
v-model指令
v-model可以在自定義指令上使用,v-model繫結父元件中的data資料。例項:
<div id="app"> <p>總數:{{ total }} </p> <my-component v-model="total"></my-component> </div> <script> Vue.component('my-component',{ template:'<button @click="handleClick">+1</button>', data:function( ){ return { counter:0 } }, methods:{ handleClick:function(){ this.counter++; this.$emit('input',this.counter); } } }); var app = new Vue({ el:'#app', data:{ total:0 } }); </script>
這段程式碼,在元件方法中的$emit()的事件名是input,並沒有在< my-component >上使用@input=“hander”,直接使用了v-model綁定了total.這是一個語法糖。
v-model 還用來建立自定義的表單輸入元件,實現資料雙向繫結。
要求:
1.接收一個value屬性
2.在有新的value時觸發input事件
例:
<div id="app">
<p>總數:{{ total }}</p>
<my-componet v-model="total"></my-component>
<button @click="handleReduce">-1</button>
</div>
<script>
Vue.component('my-component',{
props:['value'],
template:'<input :value="value" @input="updateValue">',
methods:{
updateValue:function (event){
this.$emit('input',event.target.value);
}
}
});
var app = new Vue({
el:'#app',
data:{
total:0
},
methods:{
handleReduce:function(){
this.total--;
}
}
})
</script>
非父子元件之間傳遞資料
中央事件匯流排(bus)
非父子元件之間傳遞資料其實就是靠“中介”,這就是中央事件匯流排,在Vue中推薦使用一個空的Vue例項來作為中央事件匯流排。中央事件匯流排起到了一箇中轉站的作用
例:
<div id="app">
<{{ message }}>
<component-a></component-a>
</div>
<script>
var bus = new Vue( );
Vue.component('component-a',{
template:'<button @click="handleEvent">傳遞事件</button>',
methods:{
handleEvent:function(){
bus.$emit('on-message','來自元件component-a的內容');
}
}
});
var app = new Vue({
el:'#app',
data:{
message:''
},
mounted:function(){
var _this=this;
//在例項初始化時,監聽來自bus例項的事件
bus.$on('on-message',function(msg){
_this.message = msg;
});
}
})
</script>
在例子中建立了一個bus的空vue例項,然後全域性定義了元件component-a,在建立vue例項app。在app初始化的時候,在生命週期mounted鉤子函式裡監聽了bus的事件on-message,在元件component-a中,建立了點選事件,點選按鈕,通過bus將事件on-message傳送出去,在app中使用bus.$on()接收事件,在回撥中完成自己的業務邏輯。這樣就完成了元件間的通訊。
使用中間事件匯流排可以實現任何元件間的通訊。可以深入使用bus例項,給他新增data,methods,computed等選項。
父鏈
在子元件中,使用this.$ parent可以直接訪問該元件的父例項或元件,父元件也可以通過this.$ children訪問他的所有子元件,可以遞歸向上或向下無限訪問,直到根例項或最內層的元件。
例:
<div id="app">
<{{ message }}>
<component-a></component-a>
</div>
<script>
Vue.component('component-a',{
template:'<button @click="handleEvent">通過父鏈直接修改資料</button>',
methods:{
handleEvent:function(){
//訪問到父鏈後,可以任何操作
this.$parent.message = '來自元件的內容';
}
}
});
var app = new Vue({
el:'#app',
data:{
message:' '
}
})
</script>
雖然這樣可以在父子元件之間完成通訊,但是子元件儘可能的避免以來父元件的資料,更不應該主動修改他的資料。父子元件最好還是通過props和$ emit來通訊。
子元件索引
當子元件較多時,適合用子元件索引來完成通訊。Vue提供了子元件索引的方法,用特殊的屬性ref來為子元件指定一個索引名稱。
例:
<div id="app">
<button @click="handleRef">通過ref獲取子元件例項</button>
<component-a ref="comA"></component-a>
</div>
<script>
Vue.component('component-a',{
template:'<div>子元件</div>',
data:function(){
return {
message:"子元件內容"
}
}
});
var app = new Vue({
el:'#app',
methods:{
handleRef:function(){
var msg = this.$refs.comA.message;
console.log(msg);
}
}
})
</script>
在父元件模板中,子元件標籤上使用ref指定一個名稱,並在父元件內通過this.$ refs來訪問指定名稱的子元件。$ refs只有在元件渲染完成後才填充,並且他不是響應式的。應當避免在模板或計算屬性中使用$ refs。