vue api强化学习之-------组件之间通信
除去vuex之外的方式,即vue内部组件之间的通信方式
props 和 $emit
props 是单向数据流方式,数据只能通过 props 由父组件流向子组件,而子组件并不能通过修改 props 传过来的数据修改父组件的相应状态 使用v-on在父组件引入子组件后的模板上监听子组件中的事件,$emit 可以触发使用v-on在父组件中监听的事件;
代码示例
父组件communication.vue
<template
>
<div
class="communication">
<div
>我是父组件
</div
>
<div
class="child">
<!-- 使用v
-on监听子组件中的事件 myevent
-->
<child1
:arr
="arr" @myevent
="childEmit" ></child1
>
<div
><span
>子组件传递给父组件的数据
:</span
><span
>{{childmsg
}}</span
></div
>
</div
>
</div
>
</template
>
<script
>
import Child1
from './child1.vue'
export default {
name
: 'Communication',
data(){
return {
arr
:[
{national
:'蜀国',emperor
:'刘备'},
{national
:'吴国',emperor
:'孙权'},
{national
:'魏国',emperor
:'曹操'},
],
childmsg
:"",
}
},
components
:{
Child1
,
},
methods
:{
childEmit(pra
){
this.childmsg
=pra
;
},
}
}
</script
>
子组件 child1.vue
<template
>
<div
class="child1">
<div
>我是child1
</div
>
<div
>
<span
>我是从父组件中接受到的数据
</span
>
<p v
-for="item in paraentArr" :key
="item.national">
<span
>{{item
.national
}}:</span
>
<span
>{{item
.emperor
}}</span
>
</p
>
</div
>
<button @click
="toParent">向父组件传递数据
</button
>
</div
>
</template
>
<script
>
export default {
name
: 'Child1',
props
:{
arr
:{
type
:Array
,
default:[]
}
},
data(){
return {
paraentArr
:this.arr
}
},
methods
:{
toParent(){
this.$emit("myevent","父组件接受到了吗?")
},
}
}
</script
>
$parent 和
c
h
i
l
d
r
e
n
/
children/
children/ref
通过this.
p
a
r
e
n
t
可
以
直
接
获
得
子
组
件
的
直
系
父
组
件
通
过
t
h
i
s
.
parent可以直接获得子组件的直系父组件 通过this.
parent可以直接获得子组件的直系父组件通过this.chiildren可以获得当前组件的直系子组件,不过获取到的是一个实例数组,操作不太方便,利用子组件标签的ref属性,我们可以在父组件中直接使用this.$refs.xx获取到子组件的数据和方法,
代码示例
父组件communication.vue
<template
>
<div
class="communication">
<div
>我是父组件
</div
>
<div
class="child">
<child2 ref
="child2"></child2
>
<button @click
="toChild2">向子组件传数据
</button
><br
/>
<span
>子组件传递过来的数据:
{{fromchild2
}}</span
>
</div
>
</div
>
</template
>
<script
>
import Child2
from './child2.vue'
export default {
name
: 'Communication',
data(){
return {
fromchild2
:''
}
},
components
:{
Child2
},
methods
:{
toChild2(){
this.$refs
.child2
.updatePra("父组件传递过来的值");
console
.log(this.$children
[1],".........this.$children....");
this.$children
[1].updatePra('父组件传递过来的值>>>>>>>>')
},
child2UpdateData(msg
){
this.fromchild2
= msg
;
}
}
}
</script
>
子组件 child2.vue
<template
>
<div
class="child2">
<div
>我是child2
</div
>
<div
>
<span
>我是从父组件传递过来的
:</span
>
<span
>{{fromParent
}}</span
><br
/>
<button @click
="toparent">toparent
</button
>
</div
>
</div
>
</template
>
<script
>
export default {
name
: 'Child2',
data(){
return {
fromParent
:"",
}
},
methods
:{
updatePra(msg
){
this.fromParent
= msg
},
toparent(){
this.$parent
.child2UpdateData("child2传递过来的数据,父组件收到了吗?")
}
}
}
</script
>
$on 和 $emit
$on 监听当前实例上的自定义事件 $emit 触发当前实例上的自定义事件
e
m
i
t
和
emit和
emit和on只能作用在一一对应的同一个组件实例上,因此要使用这两个方法进行组件之间的通信,则需要引入一个空的vue实例
代码示例
此示例是从child1组件向child2组件传递消息,若想要从child2向child1组件传递消息,按下面流程将触发器跟监听器再返回来写一套即可;
事件处理中心(一个空的vue实例) eventHub.js
import Vue
from 'vue';
const eventHub
= new Vue();
export default eventHub
;
子组件child1.vue (child1与child2为兄弟组件)
<template
>
<div
class="child1">
<div
>我是child1
</div
>
<div
>
<button @click
="child1ToChild2">child1向child2发送信息
</button
>
</div
>
</div
>
</template
>
<script
>
import eventHub
from './eventHub.js'
export default {
name
: 'Child1',
methods
:{
child1ToChild2(){
eventHub
.$emit("tochild2event",'从child1传递过来的消息');
}
}
}
</script
>
子组件 child2.vue
<template
>
<div
class="child2">
<div
>我是child2
</div
>
<div
>
<div
>
显示从child1中获取到的信息:
{{fromchild1
}}
</div
>
</div
>
</div
>
</template
>
<script
>
import eventHub
from './eventHub.js'
export default {
name
: 'Child2',
data(){
return {
fromchild1
:'',
}
},
mounted(){
const that
= this;
eventHub
.$on("tochild2event",function(msg
){
that
.fromchild1
= msg
;
})
},
}
</script
>
$attrs 和 $listeners
vm.
a
t
t
r
s
,
包
含
了
父
作
用
域
中
没
有
被
p
r
o
p
s
接
受
的
属
性
,
c
l
a
s
s
和
s
t
y
l
e
除
外
;
v
m
.
attrs,包含了父作用域中没有被props接受的属性,class和style除外; vm.
attrs,包含了父作用域中没有被props接受的属性,class和style除外;vm.listeners,包含了父作用域中的v-on事件监听器,不包括.native修饰符修饰的 $attrs 和
l
i
s
t
e
n
e
r
s
来
能
够
直
线
隔
代
组
件
之
间
的
消
息
互
通
,
中
间
组
件
可
通
过
v
−
b
i
n
d
=
′
listeners 来能够直线隔代组件之间的消息互通,中间组件可通过v-bind='
listeners来能够直线隔代组件之间的消息互通,中间组件可通过v−bind=′attrs’ | v-on=’$listeners’将信息直接传递给其后代组件 $listeners 和
a
t
t
r
s
两
者
表
面
层
都
是
一
个
意
思
,
attrs 两者表面层都是一个意思,
attrs两者表面层都是一个意思,attrs 是向下传递数据,$listeners 是向下传递方法,底层组件中可直接手动调用 $listeners 对象里的方法;
代码示例
父组件communication.vue
<template
>
<div
class="communication">
<div
>我是父组件
</div
>
<div
>
<span
>从孙子组件传递过来的信息:
</span
>
<span
>{{fromGrandsonMsg
}}</span
>
</div
>
<div
class="child">
<!-- 使用v
-on监听子组件中的事件 myevent grandsonCompmsg和grandEvent都是给孙子组件的
-->
<child1
:arr
="arr" @myevent
="childEmit" :grandsonCompmsg
="grandmsg" @grandEvent
="grandCallMethod"></child1
>
</div
>
</div
>
</template
>
<script
>
import Child1
from './child1.vue'
export default {
name
: 'Communication',
data(){
return {
arr
:[
{national
:'蜀国',emperor
:'刘备'},
{national
:'吴国',emperor
:'孙权'},
{national
:'魏国',emperor
:'曹操'},
],
grandmsg
:"孙子,收到我的信息了吗?",
fromGrandsonMsg
:""
}
},
components
:{
Child1
,
},
methods
:{
grandCallMethod(msg
){
this.fromGrandsonMsg
= msg
;
}
}
}
</script
>
子组件 child1.vue
<template
>
<div
class="child1">
<div
>我是child1
</div
>
<div
>
<span
>我是从父组件中接受到的数据
</span
>
<p v
-for="item in paraentArr" :key
="item.national">
<span
>{{item
.national
}}:</span
>
<span
>{{item
.emperor
}}</span
>
</p
>
</div
>
<div
>
<!-- 此处通过 v
-bind
='$attrs'和v
-on
='$listeners'向孙子组件传递数据和方法
-->
<child1
-child v
-bind
="$attrs" v
-on
="$listeners"></child1
-child
>
</div
>
</div
>
</template
>
<script
>
import Child1Child
from './child1_child.vue'
export default {
name
: 'Child1',
inheritAttrs
: false,
components
:{
Child1Child
},
props
:{
arr
:{
type
:Array
,
default:[]
}
},
data(){
return {
paraentArr
:this.arr
}
},
}
</script
>
子组件 child1_child.vue
<template
>
<div
class="child1_child">
<div
>我是child1的child
</div
>
<div
>
<span
>我是从爷爷组件中获取到的信息:
{{fromGrandfarherMsg
}}</span
>
</div
>
<button @click
="$listeners.grandEvent('爷爷,你收到我发的信息了吧')">我要给爷爷发信息
</button
>
</div
>
</template
>
<script
>
export default {
name
: 'Child1Child',
inheritAttrs
: false,
props
:{
grandsonCompmsg
:{
type
:String
,
default:""
}
},
data(){
return {
fromGrandfarherMsg
:this.grandsonCompmsg
}
},
}
</script
>
v-model 和 :xx.sync
v-model通常用在表单组件的双向数据绑定,当然,组件之前的通信也可用v-model来实现,组件之间使用v-model绑定参数时,默认绑定在value属性上,同时默认给绑定了input事件;如:相当于: 组件属性可通过sync修饰符,从而使得组件之间可进行双向的数据绑定,使用sync显示符时,此处在绑定一个属性foo时,默认绑定了一个update:foo的事件,如下所示:
代码示例
父组件 communication.vue
<template
>
<div
class="communication">
<div
>我是父组件
</div
>
<div
class="child">
<!-- v
-model给子组件绑定vmodelmsg时,同时默认绑定了input事件给子组件,子组件中使用默认使用value接受属性,也可以在子组件中使用model选项自定义接受属性名及事件名 使用$emit触发事件即可
-->
<!-- 此处使用sync绑定tosync属性的同时,默认绑定了update
:tosync事件给子组件,子组件中props中接受tosync属性即可,使用$emit('update:tosync',xx
)触发事件即可
-->
<child1
v
-model
="vmodelmsg" :tosync
.sync
="someMsg" >
</div
>
</div
>
</template
>
<script
>
import Child1
from './child1.vue'
export default {
name
: 'Communication',
data(){
return {
vmodelmsg
:"从父组件传递过来的vmodel_msg信息",
someMsg
:'从 父组件 .sync方式传递过来的信息......'
}
},
components
:{
Child1
,
},
}
</script
>
子组件child1.vue
<template
>
<div
class="child1">
<div
>我是child1
</div
>
<div
>
通过v
-model方式,从父组件传递过来的数据:
{{fromparent_vmodel
}}
<br
/>
通过sync方式,从父组件传递过来的数据:
{{fromsync
}}
<br
/>
<!-- 子改变父好像不起作用??
-->
<button @click
="changfather">vmodel事件改变父组件的值
</button
>
<button @click
="changfathersync">sync改变父组件的值
</button
>
</div
>
</div
>
</template
>
<script
>
export default {
name
: 'Child1',
inheritAttrs
: false,
model
:{
prop
:"vmodel_msg",
event
:"vmodelevent"
},
props
:{
vmodel_msg
:String
,
tosync
:String
},
data(){
return {
fromparent_vmodel
:this.vmodel_msg
,
fromsync
:this.tosync
}
},
methods
:{
changfather(){
this.$emit('vmodelevent','子改变了父中传过来的属性')
},
changfathersync(){
this.$emit('update:tosync',"sync......update..666")
}
},
mounted(){
console
.log(this,"....this...........");
}
}
</script
>
provide 和 inject
provide 选项应该是一个对象或返回一个对象的函数。该对象包含可注入其子孙的属性 inject 选项应该是:一个字符串数组,或一个对象,对象的 key 是本地的绑定名,value 是注入时的key 在父组件中通过 provider 来提供属性,然后在子组件中通过 inject 来注入变量。不论子组件有多深,只要调用了 inject 那么就可以注入在 provider 中提供的数据,而不是局限于只能从当前父组件的 prop 属性来获取数据,只要在父组件的生命周期内,子组件都可以调用。这和 React 中的 Context API 有没有很相似!
代码示例
父组件communication.vue
<template
>
<div
class="communication">
<div
>我是父组件
</div
>
<div
class="child">
<child1
></child1
>
</div
>
</div
>
</template
>
<script
>
import Child1
from './child1.vue'
export default {
name
: 'Communication',
data(){
return {
}
},
provide
:{
providePra
:[1,2,3]
},
components
:{
Child1
,
},
}
</script
>
子组件child1.vue
<template
>
<div
class="child1">
<div
>我是child1
</div
>
<div
>
<h1
>父组件中provide传递的:
{{fromParentProvide
}}</h1
>
</div
>
</div
>
</template
>
<script
>
export default {
name
: 'Child1',
inject
:{
'fromParentProvide':'providePra'
},
}
</script
>
中央事件总线EventBus
中央事件总线其实就是
o
n
和
on和
on和emit在应用上的全局使用,上面是只是在局部组件中引入使用,在全局使用测,在跟组件创建之前,先定义中央事件总线:const EventBus = new Vue();然后将中央事件总线赋值到 Vue.prototype 上,即Vue.prototype.
E
v
e
n
t
B
u
s
=
E
v
e
n
t
B
u
s
;
这
样
所
有
组
件
都
能
通
过
t
h
i
s
.
EventBus = EventBus;这样所有组件都能通过this.
EventBus=EventBus;这样所有组件都能通过this.EventBus访问到了,然后使用this.
E
v
e
n
t
B
u
s
.
EventBus.
EventBus.on和this.
E
v
e
n
t
B
u
s
.
EventBus.
EventBus.emit监听和触发事件,从而进行各种类型之间的组件通信