Vue组件通信
1. 父子组件通信
-
props
、$emit
props[父组件给子组件传递信息,子组件通过props绑定某个属性,例如title,然后父组件给title赋值,子组件通过{{title}}来显示从父组件那里获得的信息]
<template>
<div>
<h1>我是子组件</h1>
<h2>{{title}}</h2>
</div>
</template>
<script>
export default {
props:['title']
}
</script>
<style>
</style>
<!--子组件-->
<template>
<div id="app">
<h1>我是父组件</h1>
<Child :title="msg"></Child>
</div>
</template>
<script>
import Child from './Child.vue';
export default{
name:'App',
components:{
Child
},
data(){
return{
msg:'123456',
}
}
}
</script>
<style lang="less">
</style>
<!--父组件-->
$
e
m
i
t
[
子
组
件
给
父
组
件
传
递
信
息
v
m
.
emit[子组件给父组件传递信息 vm.
emit[子组件给父组件传递信息vm.$emit( event, arg )
e
m
i
t
绑
定
一
个
自
定
义
事
件
e
v
e
n
t
,
当
这
个
这
个
语
句
被
执
行
到
的
时
候
,
就
会
将
参
数
a
r
g
传
递
给
父
组
件
,
父
组
件
通
过
@
e
v
e
n
t
监
听
并
接
收
参
数
。
以
下
面
的
为
例
:
子
组
件
使
用
emit 绑定一个自定义事件event,当这个这个语句被执行到的时候,就会将参数arg传递给父组件,父组件通过@event监听并接收参数。 以下面的为例:子组件使用
emit绑定一个自定义事件event,当这个这个语句被执行到的时候,就会将参数arg传递给父组件,父组件通过@event监听并接收参数。以下面的为例:子组件使用emit定义一个事件’to-parent’,携带的参数为’我是子组件从过来的信息’,父组件中通过@to-parent监听并接收传过来的参数’我是子组件从过来的信息’,通过处理函数将传过来的参数赋值给msg,再通过{{msg}}显示出来]
<template>
<h1>子组件</h1>
</template>
<script>
export default {
mounted:function(){
this.$emit('to-parent','我是子组件从过来的信息')
}
}
</script>
<style>
</style>
<!--子组件-->
```
<template>
<h1>父组件</h1>
<h2>{{msg}}</h2>
<child @to-parent="handleToParent"></child>
</template>
<script>
import child from './Child.vue'
export default {
components: {
child
},
data(){
return{
msg:''
}
} ,
methods:{
handleToParent(msg){
this.msg=msg
}
}
}
</script>
<style>
</style>
<!--父组件-->
```
-
ref
元素或子组件注册引用信息 -
$refs
获取通过ref注册的引用ref[父组件给子组件传递信息, 如果ref用在子组件上,指向的是组件实例,可以理解为对子组件的索引,通过$ref可能获取到在子组件里定义的属性和方法。 如果ref在普通的 DOM 元素上使用,引用指向的就是 DOM 元素,通过$ref可能获取到该DOM 的属性集合,轻松访问到DOM元素,作用与JQ选择器类似。 以下面为例:在父组件中通过ref='ch'将子组件child的实例指给$ref并且通过.ch.getMessage()调用到子组件的getMessage方法,将参数传递给子组件。]
<template> <h1>父组件</h1> <h2>{{msg}}</h2> <child ref="ch"></child> </template> <script> import child from './Child.vue' export default { components: { child }, data(){ return{ msg:'' } } , mounted:function(){ this.$refs.ch.getMessage("我是父组件传过来的") } } </script> <style> </style> <!--父组件-->
<template> <h1>子组件</h1> <h2>{{message}}</h2> </template> <script> export default { data(){ return{ message:"" } }, methods:{ getMessage(msg){ this.message=msg; } } } </script> <style> </style> <!--子组件-->
-
$parent
获取当前组件的父组件实例 -
$children
获取当前组件的子组件实例vue2中使用,但是vue3中已作废
<template>
<div>
<h1>我是子组件</h1>
<h2>{{msg}}</h2>
</div>
</template>
<script>
export default {
data(){
return{
msg:'hello',
};
},
methods:{
fun(){
console.log('我是子组件'+this.$parent.msgP);
}
},
mounted(){
this.fun();
}
}
</script>
<style>
</style>
<!--子组件-->
<template>
<div id="app">
<h1>我是父组件</h1>
<Child></Child>
</div>
</template>
<script>
import Child from './Child.vue';
export default{
name:'App',
components:{
Child
},
data(){
return{
msgP:'123456',
}
},
methods:{
fun(){
console.log('我是父组件'+this.$children[0].msg);
}
},
mounted(){
this.fun();
}
}
</script>
<style lang="less">
</style>
<!--父组件-->
-
多层级父子组件通信
provide、inject
多层级通信 爷爷到孙子-传值 provide-inject
provide 选项应该是一个对象或返回一个对象的函数。
inject 选项应该是:一个字符串数组,或一个对象。
以下面为例:父组件通过provide将test的值传递给孙组件,孙组件通过inject来获取值,从而完成多层级通信。
<template>
<h1>父组件</h1>
<child></child>
</template>
<script>
import child from './Child.vue'
export default {
components: {
child
},
provide:{
test:"父组件->孙组件"
}
}
</script>
<style>
</style>
<!--父组件-->
<template>
<h1>子组件</h1>
<grandson></grandson>
</template>
<script>
import grandson from './Grandson.vue'
export default {
components:{
grandson
}
}
</script>
<style>
</style>
<!--子组件-->
<template>
<h1>孙组件</h1>
<h2>{{test}}</h2>
</template>
<script>
export default {
inject:["test"]
}
</script>
<style>
</style>
<!--孙组件-->
-
$attrs、 $listeners
$attrs: 正常情况下:父组件通过v-bind绑定一个数据传递给子组件,子组件通过props接收到就可以在子组件的html中使用了。但是,如果父组件v-bind传递给子组件,子组件没有用props接收呢? 注意:这个时候,父组件传递过来的数据就会被挂载(赋值)到这个子组件自带的对象$attrs上面,所以: $attrs就是一个容器对象,这个容器对象会存放:父组件传过来的且子组件未使用props声明接收的数据 。 爷组件传递给孙组件的逻辑流程 其实,爷组件传递给孙组件的逻辑流程就是,通过爷组件首先传递给父组件,当然父组件不在props中接收,那么爷组件传递给父组件的数据就会存放到父组件的$attrs对象中里面了,然后,再通过v-bind="$attrs",再把这个$attr传递给孙组件,在孙组件中使用props就能接收到$attrs中的数据了,这样就实现了,祖孙之间的数据传递。
<template>
<h1>父组件</h1>
<child :msg="msg"></child>
</template>
<script>
import child from './Child.vue'
export default {
components: {
child
},
data() {
return {
msg:'我是父组件'
}
}
}
</script>
<style>
</style>
<!--父组件-->
<template>
<h1>子组件</h1>
<h2>{{$attrs.msg}}</h2>
<grandson v-bind="$attrs"></grandson>
</template>
<script>
import grandson from './Grandson.vue'
export default {
components:{
grandson
}
}
</script>
<style>
</style>
<!--子组件-->
<template>
<h1>孙组件</h1>
<h2>{{msg}}</h2>
</template>
<script>
export default {
inheritAttrs: false,
props:['msg']
}
</script>
<style>
</style>
<!--孙组件-->
$listeners
使用$listeners可以实现孙组件的数据传递到父组件中去,逻辑的话,也是用在中间的桥梁子组件上面去,我的理解就是$listeners可以将孙组件emit的方法通知到父组件。
第一步,在中间的子组件中加上$listenners
<Son v-on="$listeners" @toGp="handleFun"></Son>
第二步,父组件中定义事件方法
<template>
<div id="app">
<h1>我是父组件</h1>
<h2>{{msgP}}</h2>
<Child @toGp="handleFun"></Child>
</div>
</template>
<script>
import Child from './Child.vue';
export default{
name:'App',
components:{
Child
},
data(){
return{
msgP:'123456',
}
},
methods:{
handleFun(val){
this.msgP=val;
}
},
}
</script>
<style lang="less">
</style>
<!--父组件-->
第三步,孙组件去触发事件方法即可
<template>
<div>
<h1>我是孙组件</h1>
<h2>{{msg}}</h2>
</div>
</template>
<script>
export default {
data(){
return{
msg:'hello'
}
},
methods:{
p(){
this.$emit('toGp',this.msg);
}
},
mounted(){
this.p();
}
}
</script>
<style>
</style>
<!--孙组件-->
<template>
<div>
<h1>我是子组件</h1>
<h2>{{msg1}}</h2>
<Son v-on="$listeners" @toGp="handleFun"></Son>
</div>
</template>
<script>
import Son from './Son.vue';
export default {
components:{
Son
},
data(){
return{
msg1:'hello',
};
},
methods:{
handleFun(val){
this.msg1=val;
}
},
}
</script>
<style>
</style>
-
非关系组件通信
EventBus
又称为事件总线
https://zhuanlan.zhihu.com/p/72777951里边介绍了事件总线的创建,提交事件,接受事件,销毁对应的事件监听者;
https://blog.csdn.net/weixin_53965547/article/details/124399124这里介绍了vue2创建使用事件总线。
接下来附上例子:
//main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App),
beforeCreate(){
Vue.prototype.$bus=this;
}
}).$mount('#app')
<template>
<div id="app">
<h1>我是父组件</h1>
<Child></Child>
</div>
</template>
<script>
import Child from './Child.vue';
export default{
name:'App',
components:{
Child
},
methods:{
p(){
this.$bus.$emit('myhub','hello');
}
},
mounted(){
this.p();
}
}
</script>
<style lang="less">
</style>
<!--父组件-->
<template>
<div>
<h1>我是子组件</h1>
<h2>{{msg1}}</h2>
</div>
</template>
<script>
import Son from './Son.vue';
export default {
components:{
Son
},
data(){
return{
msg1:'',
};
},
methods:{
f(){
this.$bus.$on('myhub',data=>{
this.msg1=data;
})
}
},
mounted(){
this.f();
}
}
</script>
<style>
</style>
<!--子组件-->