vue中比较重要的就是组件了。而组件随处可复用的特性,使得组件通讯很是重要。那么组件之间通信方式有哪些呢?html
第一种:父子组件通信:vue
若是是 html页面 中全局注册的组件 和 实例中局部注册的组件ajax
HTML:数组
<div id="box"></div>
JS:异步
Vue.component('child',{ name:'child', props:{ msg:{ type:String, require:true } }, template:` <div id='getChild'> <h3>我是child组件</h3> <p>{{msg}}</p> <button @click='getParentVal'>点击获取父组件内容</button> <button @click='sendVal'>向父组件传递内容</button> </div> `, data:function(){ return { childVal:'我是子组件中的数据' } }, methods:{ //这里是获取父组件中的属性或方法 getParentVal:function(){ console.log(this.$parent.age) }, //这个是向父组件传递指定的内容 sendVal:function(){ this.$emit('sendChild',{ mssg:'我是子组件$emit传过来的内容' }) } } }) Vue.component('myParent',{ name:'parent', template:` <div> <button @click='getVal'>点我获取子组件内容</button> <child :msg='parentVal' ref='getChild' @sendChild='getSendChild'></child> </div> `, data:function(){ return { parentVal:'我是parent组件传过来的值', age:666 } }, methods:{ //这个是获取子组件的属性或方法 getVal:function(){ console.log(this.$refs.getChild.childVal) }, //这个是获取子组件经过emit传递过来的内容 getSendChild:function(res){ console.log(res) } } }) new Vue({ el:'#box',
//这里局部注册父组件
template:`
<my-parent></my-parent>
`
})
注意事项:ide
1) 组件须要先注册才能使用,注册又分 局部注册 和 全局注册。局部注册须要在实例里面的template声明组件的内容,全局注册即如上例同样。函数
2) 组件名支持驼峰,小写,大写,横线(xxx-xxx)的写法。可是在使用组件的时候,若是是驼峰的写法,则需要写成横线的形式。如上面 组件名是myParent ,那么使用的时候 就必须是 <my-parent></my-parent> 。ui
3) 父组件能够获取子组件的数据和方法,经过在引用子组件的时候定义 ref='自定义名称' ,而后在子组件的template中最外层节点,定义一个id值,而后父组件中使用 this.$refs.自定名称.子组件数据 。就如同上例点击获取子组件数据同样。或者不加ref,直接使用 this.$children[第几个子组件].子组件数据。this
4) 子组件能够获取父组件的数据和方法,在子组件中使用 this.$parent.子组件数据。es5
5) 子组件经过 $emit('自定义名称',数据) 来达到向父组件传递指定的数据,相似 jQuery 的 trigger 。
6) 父组件经过 实例.$on('对应emit定义的名称',function(res){}) 或者 在引用子组件的时候 <child @对应emit定义的名称='本身定义的函数名'></child> ,而后在methods中指定 本身定义的函数名 获取到的 res 就是子组件传过来的值。
7) template 里面的内容 能够用 ` ` 就是键盘上 esc 下面的那个波浪键 在英文状态下打出来的内容 ,这样就不用向es5同样用 + 加号和 ' ' 引号来合并成字符串了。
8) props 中命名方式 不支持 xxx-xxx 这种横线的格式,支持驼峰,小写。若是props中是驼峰的命名方式,那引用组件的时候就要写成对应的横线方式,例如props:[getPhone] 那么<child get-phone='xxx'></child> ,若是绑定的是动态值也是同样的写法<child :get-phone='xxx'></child> 。缘由:因为html不区分大小写的特性,因此无法对应组件中的驼峰名称。
9) 为何组件中的data必须是函数,而后返回对象?由于组件是用于复用的,彼此之间的数据必定要是惟一的。因此若是data就是一个对象,那么因为对象是引用类型,不一样地方引用同一个对象,并非引用的值,而是引用的对象的地址,因此某一处修改以后,其它的也会跟着变化,这样就不能达到数据惟一的目的。而使用函数再返回一个对象,每一个对象的地址都是不一样的,就能保证每次都是一个新的对象。
10)props验证方式的写法能够查看官网,里面的prop验证
11) template 里面的内容必须只有一个根元素。
若是是 .vue 这种单文件模块 的组件
这种方式和 html 页面 中注册组件有稍许的不同。
//child 组件 <template> <div> xxxx </div> </template> <script> export default { props:[], data:function(){} } </script> <style> </style>
//parent 组件 <template> <div> <childComponent></childComponent> //若是注册的时候不重命名的话就可使用<child></child> </div> </template> <script> import child from 'xxx' export default { data:function(){}, components:{ 'childComponent':child //若是不重名的话能够直接是{child} }, data:function(){} } </script> <style> </style>
说明:
1) 每一个 .vue单文件组件模块,都须要在 template 中声明组件的内容,而且也只有一个根元素。
2) 在script 里面 须要 export default 组件注册的必须内容,例如props,data,mthods等。
3) 在须要引入组件的页面 import 自定义组件名称 from 'xxx' 。组件的名称自定义,支持大写,小写,驼峰,横线(xxx-xxx)。
4) import 组件以后,还须要在components中注册组件。注册的时候也能够重命名组件名称。
5) 除了上面的区别,其它的就没什么区别了,组件的通信也和上面 html页面中组件通信同样的处理方式。
第二种:非父子组件之间的通信。
在 html 页面中,注册方式与父子组件无差异,也是全局注册和局部注册。
HTML:
<div id="box"></div>
JS:
//全局注册mine组件 Vue.component('mine',{ template:` <div> 我是mine组件 <button @click='sendToBrother'>点击向brother组件发送内容</button> </div> `, data:function(){ return { name:'mine', sex:'male' } }, mounted:function(){ //接收mine组件传过来的内容 transfer.$on('brotherVal',function(res){ console.log(res) }) }, methods:{ //向brother组件传递内容 sendToBrother:function(){ transfer.$emit('mineVal',this.name) } } }) //全局注册brother组件 Vue.component('brother',{ template:` <div> 我是brother组件 <button @click='sendToMine'>点击向mine组件发送内容</button> </div> `, data:function(){ return { name:'brother', age:666 } }, mounted:function(){ //接收mine组件传过来的内容 transfer.$on('mineVal',function(res){ console.log(res) }) }, methods:{ //向mine组件发送内容 sendToMine:function(){ transfer.$emit('brotherVal',this.name) } } }) //这是最重要的一步,定一个空的实例对象。 var transfer=new Vue(); new Vue({ el:'#box', data:{}, //局部注册两个组件 template:` <div> <mine></mine> <brother></brother> </div> ` })
说明:
1) 主要的就是经过一个 中间实例对象来实现 非父子组件之间的通信
2) 仍是经过 $emit() 来发送内容 , $on() 来接收传递过来的内容 ,只是使用这两个方法的对象并非 this 而是 一个空的实例对象。要注意 $on 和 $emit 中的事件名要对应
3) 不必定是mounted的时候才去接收传过来的内容,created的时候也是能够的。应该是只要生命周期里,数据初始化完成以后都行。
4) 具体是什么原理,我不清楚。也感受不必去搞懂
若是是 .vue 这种单文件模块 的组件
这种方式和 html 页面 中注册组件有稍许的不同。并且通信的方式也有一点差距。
第一步:须要中间实例对象,因而新建一个 transfer.js
import Vue from 'vue' export default new Vue();
第二步:须要传值的页面,引入这个js
//mine 组件 <template> <div> <button @click='sendToBrother'>点我向brother组件发送内容</button> </div> </template> <script> import transfer from 'transfer.js的路径' export default { data:function(){ return {} }, methods:{ sendToBrother:function(){ transfer.$emit('sendVal','这是mine组件传过来的值') } } } </script> <style> </style>
//brother 组件 <template> <div> xxx </div> </template> <script> import transfer from 'transfer.js的路径' export default { data:function(){ return {} }, mounted:function(){ transfer.$on('sendVal',function(res){ console.log(res) }) } } </script> <style> </style>
第三步:在引用这两个组件的地方,注册这两个组件。
//引入组件的页面 <template> <div> <mine></mine> <brother></brother> </div> </template> <script> import mine from 'mine组件的路径'; import brother from 'brother组件的路径' export default { data:function(){ return {} }, components:{ mine ,brother }, } </script> <style> </style>
说明:
1) 实现的方式仍是差很少的 , 都是 $on 接收内容 $emit 发送内容。
2) 只是中间实例对象须要添加到一个 js 中。而后两个组件页面都须要引入。
3) 这种经过中间实例对象的方式,也能够用于 父子、祖孙 等关系的组件通信。
上面的通信方式是最多见的。可是在组件通信这块,vue 2.4 版本又增长了 inheritAttrs、attrs和listeners 。这三个的用法,后面再找个机会补上。
若是遇到 父级组件须要传给 子级组件的props值 是经过 ajax 异步请求 传入的 。那么,在子组件的生命周期中获取该props内容是获取不了的。就算是在mounted 中也是获取不了的。
这个时候的解决办法是:
<childComponent :sendVal='getval' v-if='getval'></childComponent>
必定要加一个 v-if ,这样才能在 子组件的 mounted 中获取到该值。这个地方是把我坑惨的。。。网上有推荐说若是是数组,可使用 v-if = 'getval.length' 。这彻底不必,并且有可能还会报错,由于getval的值有可能还没返回来,再去取length确定会报错。 若是是布尔值的话,更要注意点。