所谓组件间的通信,实际上就是指在各个组件间,进行参数或者信息的相互传递。比如我们前面学的通过props给子组件传参,实际上这就是父组件向子组件进行单向的通信。
1.父到子的通信
父到子的通信使用我们前面使用的props即可。
2.子到父的通信
父子组件的概念
父组件:主动发起调用的哪一方。父组件一般可以给子组件传参
子组件:被调用的哪一方。子组件可以接受父组件传来的参数
例如:
当我们在一个vue实例绑定的div中使用自定义组件component1,那么
这个vue实例就是父组件,被调用的component1就是子组件。
当子组件需要向父组件通信时,原理与流程类似于下面的描述:
1.在父组件中定义一个可以接受子组件信息的方法
2.然后把这个方法类似于传参一样传入子组件,(v-on+自定义事件名绑定)
3.在子组件就获取此方法,并进行传参调用来修改父组件内容。this.$emit(事件名,参数)
其实说白了,真正执行修改父组件的数据的代码还是定义在父组件的方法中的,只是由子组件触发并调用了而已。
在下图中我定义了一个自定义的事件:my-handle,靠他来实现子向父的传参
初始化运行结果:
点击子组件中的按钮后
**关于 e m i t 方 法 ∗ ∗ 其 中 文 含 义 : [ 发 出 ; 发 射 ; 颁 布 ; 发 表 ] , 在 v u e 中 作 用 : 用 于 调 用 触 发 父 组 件 传 递 的 自 定 义 事 件 . 调 用 形 式 : t h i s . emit方法** 其中文含义: [发出;发射;颁布;发表], 在vue中作用: 用于调用触发父组件传递的自定义事件. 调用形式: this. emit方法∗∗其中文含义:[发出;发射;颁布;发表],在vue中作用:用于调用触发父组件传递的自定义事件.调用形式:this.emit(自定义事件名,参数(可选))
1.在组件标签标签上通过v-on绑定事件,如果未做声明那么绑定的就会是自定义事件,哪怕和原生事件名称一样。
如果要在在组件上监听原生DOM事件,可使用修饰符:.native对事件进行修饰,这样就可绑定原生DOM事件。
以click事件为例,在组件上绑定原生click事件,绑定就是包裹组件所有内容的最外层根元素,即click是绑定在该组件的最外层元素上的。
虽然这个很少用,但是不得不说在某些时候特别有用。
概述
当我们使用input事件作为事件名时,只要没有加上,native修饰符,那么就会作为自定义事件处理。
还是刚才的代码,我们只是把自定义事件的名称由 my-handle
变为了 input
,然后执行,结果和刚才的一样。
然后这里就是我要说的了,当我们使用@input作为自定义事件名时,我们其实可以使用语法糖来简化代码
简化点:
1.可以去掉父组件中函数
2.在子组件标签上绑定时,可以使用v-model绑定,由于去掉了函数只需要绑定要改变的那个值就可以了。
当然,虽然我们使用的是v-model指令,但是这是@input事件的语法糖写法,所以我们还是需要在$emit方法里面写input事件名。
等价于
methods:{
mesv:function(v){
this.mes=v;
}
}
直接用语法糖v-model绑定一个计算属性
上面我们在v-model绑定的直接就是一个简单的实例变量,其实我们也可以直接绑定一个计算属性。这样可以应对一些比较复杂的情况。
v-model与表单子组件-----双向绑定
原理:在子组件的input事件上绑定,监听子组件事件的变化,变了就马上向父组件传值…
当只有一个输入框时,直接使用v-model绑定
当是一个完整的表单,有多个输入框时,使用@input绑定
Html代码
登录组件代码
提示:也可以直接使用一个对象与表单绑定,实现双向绑定效果。
在vue1中的通信方式(已经被废弃)
对于【祖先和后代】组件的通信,采取的是 d i s p a t c h ( ) 方 法 和 dispatch()方法和 dispatch()方法和broadcast()方法实现。
$dispatch()方法: 用于向祖先级级派发事件
$broadcast()方法:用于向子孙级派发事件
然后接受事件方组件只要添加一个选项:events(他和data同级),这样在这个选项里面就可以收到此事件信息了。
然后这两个方法发出后,在那个方向线上(祖先至后代)的任何组件都可以接受到,不过事件本身会按照就近原则传递,且会在第一次接收时停止冒泡,除非返回true.
Document
{{mes}}
缺点: 这两个方法虽然看起来很好用,但是缺点太明显了。
1.他不能解决兄弟间组件的通信
2.在组件结构扩展的过程中,这种方式的可用性会变得越来越脆弱。
所以,在vue2中这种方式被废弃了!
在vue2中的通信方式(主流用法)
在vue2中,推荐使用一个空的vue实例作为中央事件总线
,来负责所有的信息转发。类似于中介。(其实也就是设计者模式的观察者模式)
这种方式要求如下:
1.创建一个作为中介的vue实例。 var bus=new Vue();
2.所有组件都把要发的信息发给中介实例.
bus.$emit(事件名,参数)
3.所有相关组件监听中介实例是否接收到了信息,好及时获取。
bus.$on(事件名,回调函数)
由于中介实例能被任何组件访问,所以也就实现了任意组件间的通信。
定义一个空的中央事件总线实例(类似于中介)
var bus = new Vue();
定义一个全局组件
创建一个vue实例,作为父组件
父组件所绑定的网页模板代码
提示:
其他兄弟组件、跨多级的任意组件,通信方式都是如此。
1.需要发信息的组件,使用bus.$emit()方法向中央事件总线传值就可以了
2.需要收消息的组件,使用bus.$on()方法向中央事件总线对象取值就可以了
3.在组件向中央事件总线监听是否有收到值时,应该把监听写在mounted生命周期函数里面,好确保在组件渲染完成后才开启监听的,避免出现异常。
4.这种方法实现了任何组件间的通信,如果深入使用,可以扩展bus实例,给它添加data、computed、methods等选项,这些都是可以公用的,在业务中,尤其是协同开发时非常有用,因为经常需要共享一下通用信息,比如用户名,token等。对于这些信息只要在初始化时让bus获取一次,任何时间,任何组件都可以直接使用了(常用语spa单页应用模式)
父链和子链是一种父子间组件通信的新方式。
概念
父链:
在子组件中,使用this.$parent可以直接访问该组件的父实例或组件,【类似于原生或者jquery中获取父节点的方式】
子组件:
在父组件中,使用this.$children访问它所有的子组件,当子组件较多时可以通过子组件索引名称来实现查找。【类似于原生或者jquery中获取子节点的方式】
说明
1.this.$parent与this.$children可以无限的向上或向下访问,直到根实例或最内层组件。
2.然后由于子组件可以有多个,this.$children获取子组件时,获取的的是一个数组,要给上下标才能获取到具体的某一个子组件。
3.这时操作起来不是很方便,我们就可以使用:子组件索引的方式实现获取具体子组件
父链实例
子链实例
子组件索引实例
给子组件定义索引时,需要在子组件调用标签上使用ref属性定义,如:
然后在父组件中获取时,通过this.$refs.refName的方式获取具体的子组件,然后.$refs只在组件渲染完成后才会充填。
this.$refs.sub2.submes = "来自父组件的信息--sub2";
由于$refs是非响应式的,所以他仅仅作为直接访问子组件的一个应急方案。应当避免在计算属性或者模板中使用$refs.
父链和子链总结
1.父链与子链的父子组件通信方式非常相似与传统的dom节点通信方式,当然他仍然没有去操作dom节点,他操作的仍然是数据。
2.不过这种方式会让父子组件间出现 紧耦合 子看父组件或子看子组件很难他们的状态,因为他随时可能会被任意组件修改,所以这种方式并不推荐!
3.父子组件通信最好还是使用props与【自定义事件+$emit】的方式来通信。
4.跨级组件间的通信还是使用中央事件总线的方式实现通信。【bus.$emit(),bus.$on()】