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。

猜你喜欢

转载自blog.csdn.net/ma_shen/article/details/84036624