组件通信
概述
所谓组件间的通信,实际上就是指在各个组件间,进行参数或者信息的相互传递。比如通过props给子组件传参,实际上这就是父组件向子组件进行单向的通信
组件通信的几种方式
(一)父到子的通信
父到子的通信使用props即可,在以前的博客中我有详细的讲解,不懂可以去看一下
(二)子到父的通信
①父子组件的概念
父组件:主动发起调用的哪一方,父组件一般可以给子组件传参
子组件:被调用的哪一方,子组件可以接受父组件传来的参数
例如:当我们在一个vue实例绑定的div中使用自定义组件component,那么这个vue实例就是父组件,被调用的component就是子组件
②子组件向父组件通信流程
- 在父组件中定义一个可以接受子组件信息的方法
- 然后把这个方法类似于传参一样传入子组件,(v-on+自定义事件名绑定)
<h1>{{message}}</h1>
<son-component v-on:method='changeMes'></son-component>
- 在子组件就获取此方法,并进行传参调用来修改父组件内容,用this.$emit(事件名,参数)
$emit方法中附加参数都会传给监听器回调
点击子组件中定义的按钮
其实说白了,真正执行修改父组件的数据的代码还是定义在父组件的方法中的,只是由子组件触发并调用了而已
③扩展一:在组件标签上绑定原生事件
在组件标签标签上通过v-on绑定事件,如果未做声明那么绑定的就会是自定义事件,哪怕和原生事件名称一样,下面@click的代码就无法触发我们平常认知的onclick点击事件:
<son-component @click='fn' v-on:method='changeMes'></son-component>
上面的代码并不会执行点击事件, 如果要在在组件上监听原生DOM事件,可使用修饰符.native对事件进行修饰,这样就可绑定原生DOM事件,更改为:
<son-component @click.native='fn' v-on:method='changeMes'></son-component>
效果图
④扩展二:自定义事件@input的语法糖——v-model
当我们使用input事件作为事件名时,只要没有加上.native修饰符,那么就会作为自定义事件处理
因为v-mdel语法糖中实际包含了@input事件,这样我们就可以直接使用v-model来绑定
效果图
用v-model的简化点
- 可以去掉父组件中函数
- 在子组件标签上绑定时,可以使用v-model绑定,由于去掉了函数只需要绑定要改变的那个值就可以了
不明白的可以直接参考我关于v-model语法糖的文章 点击这里
⑤直接用语法糖v-model绑定一个计算属性
⑥当子组件有一个完整的表单时,可以使用@input绑定计算属性实现
<body>
<div id="app">
action:【{{action}}】<br>
username:【{{username}}】<br>
password:【{{password}}】<br>
<login-component
:action = 'action' :username = 'username'
:password = 'password' @input = "fromChange">
</login-component>
</div>
<script>
Vue.component('login-component',{
props:['action','username','password'],
data:function(){
return{
actionv:this.action,
usernamev:this.username,
passwordv:this.password,
}
},
template:`
<div>
<form :action="actionv" @input="sendform">
<input type="text" name="username" v-model="usernamev"/></br>
<input type="password" name="password" v-model="passwordv"></br>
<input type="submit" />
<input type="reset" />
</form>
</div>`,
methods:{
sendform:function(){
this.$emit('input',this.usernamev,this.passwordv)
}
}
})
var vueApp = new Vue({
el:'#app',
data:{
username:'goudan',
password:123456,
action:'https://www.baidu.com'
},
methods: {
fromChange:function(username,password){
this.username = username;
this.password = password;
}
},
})
</script>
</body>
效果图
(三)任意组件之间的通信
在vue2中,推荐使用一个空的vue实例作为中央事件总线,来负责所有的信息转发。类似于中介。(其实也就是设计者模式的观察者模式)
通信流程
1. 创建一个作为中介的vue实例
var bus=new Vue();
2. 所有组件都把要发的信息发给中介实例——bus.$emit(事件名,参数)
3. 所有相关组件监听中介实例是否接收到了信息,好及时获取——bus.$on(事件名,回调函数)
由于中介实例能被任何组件访问,所以也就实现了任意组件间的通信
效果图
代码:
<body>
<div id="app">
<div>
<p>父组件键中接收到的消息:{{parentmes}}</p>
<button @click=toSon>向子组件传值</button>{{message}}
</div>
<son-component></son-component>
</div>
<script>
var bus = new Vue(); //中央事件总线
//创建一个子组件
Vue.component('son-component', {
template: `<div>
<p>子组件键中接收到的消息:{{sonmes}}</p>
<button @click='toParent'>向父组件传值</button>{{message}}
</div>`,
data: function () {
return {
sonmes: '',
message: '子组件'
}
},
methods: {
toParent: function () {
bus.$emit('son-news', '来自子组件son-component的内容');
}
},
mounted: function () {
var _this = this;
bus.$on('parent-news', function (v) {
_this.sonmes = v;
})
},
})
//创建一个vue实例,作为父组件
var vueApp = new Vue({
el: '#app',
data: {
parentmes: '',
message: '父组件'
},
methods: {
toSon: function () {
bus.$emit('parent-news', '来自父组件的内容');
}
},
mounted: function () {
var _this = this;
bus.$on('son-news', function (v) {
_this.parentmes = v;
})
},
})
</script>
</body>