1. 程式人生 > >vue中元件間的通訊

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。