【vue组件通信】

本文详细介绍了Vue.js中组件间通信的多种方法,包括props(父到子)、$emit(子到父)、refs(子到父)、$parent(父到子)、$children(子到父)、slot(内容分发)、$attrs(爷孙传值)以及$listeners(孙子到爷爷)。此外,还特别提到了使用bus进行跨级组件通信的实践案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

vue组件通信,传值方法梳理

1. props ( 父=>子 )
步骤:

  • 创建父子组件
  • 在子组件组件中添加props属性,值可以是数组或者对象形式
  • 父组件给子组件传值
    示例:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .father{
            width: 300px;
            height: 200px;
            background-color: aqua;
        }
        .son{
            width: 200px;
            height: 100px;
            background-color: brown;
        }
    </style>
</head>
<body>
    <div id="app">
        <Father class="father"></Father>
    </div>
    <!-- 父组件 -->
    <template id="father">
        <div>
            <p>父组件中的msg : {{ msg }}</p>
            <Son class="son" :txt="msg"></Son>
        </div>        
    </template>
    <!-- 子组件 -->
    <template id="son">
        <div>
            <p>子得到的值 :{{ txt }}</p>
        </div>        
    </template>
</body>
</html>
<script src="./lib//vue.js"></script>
<script>
    // 创建实例
    var vm = new Vue({
        el: '#app',
        data:{},
        methods: {},
        components: {
            Father:{
                template:'#father',
                data(){
                    return{
                        msg:'父组件需要传给子组件的msg',
                    }
                },
                components:{
                    Son:{
                        template:'#son',
                        data(){
                            return{
                               byFather:this.txt ,
                            }
                        },
                        props:{
                            txt:{
                                type:[Number,String],
                            }
                        }
                    }
                }
            }
        }
    })
</script>

在这里插入图片描述
2. $emit ( 子 => 父 )
步骤:

  • 编写父子组件
  • 在子组件模板中编写给父组件传值的按钮 绑定点击事件
  • 编写子组件中传值的方法
  • 在父组件调用子组件的位置,监听自定义事件
  • 编写监听事件对应的方法
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .father{
            width: 300px;
            height: 200px;
            background-color: aqua;
        }
        .son{
            width: 200px;
            height: 100px;
            background-color: brown;
        }
    </style>
</head>
<body>
    <div id="app">
        <Father class="father"></Father>
    </div>
    <!-- 父组件 -->
    <template id="father">
        <div>
            <p>父组件接收子的值 : {{ msg }}</p>
            <Son class="son" @to_father="acceptSon"></Son>
        </div>
    </template>
    <!-- 子组件 -->
    <template id="son">
        <div>
            <button @click="giveFather">{{ txt }}</button>
        </div> 
    </template>
</body>
</html>
<script src="./lib//vue.js"></script>
<script>
    // 创建实例
    var vm = new Vue({
        el: '#app',
        data:{},
        methods: {},
        components: {
            Father:{
                template:'#father',
                data(){
                    return{
                        msg:''
                    }
                },
                methods:{
                    acceptSon(v){
                        console.log(v);
                        this.msg = v 
                    }
                },
                components:{
                    Son:{
                        template:'#son',
                        data(){
                            return{
                                txt:'子组件需要传给父组件的msg',
                            }
                        },
                        methods:{
                            giveFather(){
                                this.$emit('to_father',this.txt)
                            }
                        }
                    }
                }
            }
        }
    })
</script>

在这里插入图片描述

3. refs ( 子 => 父 )

  1. ref 加在普通的元素上,用this.$refs.ref值 , 获取到的是dom元素。
  2. ref 加在子组件上,用this.$refs.ref值 , 获取到的是组件实例,可以使用组件的所有方法、属性。
    示例:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .father{
            width: 300px;
            height: 200px;
            background-color: aqua;
        }
        .son{
            width: 200px;
            height: 100px;
            background-color: brown;
        }
    </style>
</head>
<body>
    <div id="app">
        <Father class="father"></Father>
    </div>
    <!-- 父组件 -->
    <template id="father">
        <div>
            <p>父获取到的值:{{msg}}</p>
            <button @click="getRef">借助ref获取子的值</button>
            <Son ref="son" class="son"></Son>
        </div>
    </template>
    <!-- 子组件 -->
    <template id="son">
        <div>
            <p>子=>父: {{ gift }}</p>
        </div> 
    </template>
</body>
</html>
<script src="./lib//vue.js"></script>
<script>
    // 创建实例
    var vm = new Vue({
        el: '#app',
        data:{},
        methods: {},
        components: {
            Father:{
                template:'#father',
                data(){
                    return{
                        msg:''
                    }
                },
                methods:{
                    getRef(){
                       console.log(this.$refs);
                       console.log(this.$refs.son.gift); //茅台
                       this.msg = this.$refs.son.gift;
                    }
                },
                components:{
                    Son:{
                        template:'#son',
                        data(){
                            return{
                                gift:'茅台'
                            }
                        },
                        methods:{ }
                    }
                }
            }
        }
    })
</script>

在这里插入图片描述
4.$parent ( 父 => 子 )

this.$parent,可以获取到当前组件的父组件实例,即,可以直接调用使用父组件内的方法、属性、一切。
示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .father{
            width: 300px;
            height: 200px;
            background-color: aqua;
        }
        .son{
            width: 200px;
            height: 100px;
            background-color: brown;
        }
    </style>
</head>
<body>
    <div id="app">
        <Father class="father"></Father>
    </div>
    <!-- 父组件 -->
    <template id="father">
        <div>
            <p >父=>子 的值: {{msg}}</p>
            <Son class="son"></Son>
        </div>
    </template>
    <!-- 子组件 -->
    <template id="son">
        <div>
            <button @click="getParent">借助$parent获取父组件的值</button>
            <p>子组件获取到的值: {{ txt }}</p>
        </div> 
    </template>
</body>
</html>
<script src="./lib//vue.js"></script>
<script>
    // 创建实例
    var vm = new Vue({
        el: '#app',
        data:{},
        methods: {},
        components: {
            Father:{
                template:'#father',
                data(){
                    return{
                        msg:'父组件的值'
                    }
                },
                methods:{ },
                components:{
                    Son:{
                        template:'#son',
                        data(){
                            return{
                                txt:''
                            }
                        },
                        methods:{
                            getParent(){
                                console.log(this.$parent);
                                console.log(this.$parent.msg); //父组件的值
                                this.txt = this.$parent.msg;
                            }
                         }
                    }
                }
            }
        }
    })
</script>

在这里插入图片描述
5. $children ( 子 => 父 )

vm.$children可以获取到所有的子组件以数组形式展现,可以通过下标获取对应组件的实例属性方法。
示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .father{
            width: 300px;
            height: 200px;
            background-color: aqua;
        }
        .son{
            width: 200px;
            height: 100px;
            background-color: brown;
        }
    </style>
</head>
<body>
    <div id="app">
        <Father class="father"></Father>
    </div>
    <!-- 父组件 -->
    <template id="father">
        <div>
            <p >父获取到的值: {{msg}}</p>
            <button @click="getSon">借助$children获取子组件的值</button>
            <Son class="son"></Son>
        </div>
    </template>
    <!-- 子组件 -->
    <template id="son">
        <div>
            <p>子=>父 的值: {{ gift }}</p>
        </div> 
    </template>
</body>
</html>
<script src="./lib//vue.js"></script>
<script>
    // 创建实例
    var vm = new Vue({
        el: '#app',
        data:{},
        methods: {},
        components: {
            Father:{
                template:'#father',
                data(){
                    return{
                        msg:''
                    }
                },
                methods:{
                    getSon(){
                        console.log(this.$children);
                        this.msg = this.$children[0].gift;
                    }
                 },
                components:{
                    Son:{
                        template:'#son',
                        data(){
                            return{
                                gift:'青花'
                            }
                        },
                        methods:{ }
                    }
                }
            }
        }
    })
</script>

在这里插入图片描述

6. slot 插槽 ( 另外再具体介绍)
匿名插槽:
具名插槽: (vue2.6以后插入具名插槽)

7.$attrs:爷孙传值
步骤:

  • 爷爷组件把想要传递给孙子组件的值,通过自定义属性值的方式,即传统的正向传值方式,传递给父组件
  • 父组件可以通过props接受父组件想要的数据,父组件中没有使用props接受的值,可以通过$attrs传递给孙子组件
  • a t t r s 添加在父组件模板调用孙子组件的位置,给孙子组件添加 ‘ v − b i n d = ′ attrs添加在父组件模板调用孙子组件的位置,给孙子组件添加`v-bind=' attrs添加在父组件模板调用孙子组件的位置,给孙子组件添加vbind=attrs’`,
  • 孙子组件在自己的组件中,使用props,接收爷爷组件传递给父组件的值,(父组件没有用pros接收的值)
    示例:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .grandfa{
            width: 500px;
            height: 400px;
            background-color: rgb(246, 255, 0);
        }
        .father{
            width: 450px;
            height: 240px;
            background-color: aqua;
        }
        .son{
            width: 400px;
            height: 100px;
            background-color: rgb(243, 95, 95);
        }
    </style>
</head>
<body>
    <div id="app">
        <Grandfa class="grandfa"></Grandfa>
    </div>
    <!-- 爷爷组件 -->
    <template id="grandfa">
        <div>
            <h1>爷爷组件</h1>
            <p>爷爷 => 孙子:{{msg0}},{{msg1}}</p>
                    <!-- 注意 givevals1: 不可用驼峰命名法(giveVals1:报错),可保持小写或用下划线give_vals1-->
            <Father :givevals1="msg0" :givevals2="msg1"></Father>
        </div> 
    </template>
    <!-- 父组件 -->
    <template id="father">
        <div  class="father">
            <h1>父组件</h1>
            <p>通过props接收的值giveVals1: {{ givevals1 }}</p>
            <Son v-bind="$attrs"></Son>
        </div>
    </template>
    <!-- 子组件 -->
    <template id="son">
        <div  class="son">
            <h1>孙子组件</h1>
            <p>接收爷爷组件的giveVals2:{{ givevals2 }}</p>
        </div> 
    </template>
</body>
</html>
<script src="./lib//vue(1).js"></script>
<script>
    // 创建实例
    var vm = new Vue({
        el: '#app',
        data:{},
        methods: {},
        components: {
            Grandfa:{
                template:'#grandfa',
                data(){
                    return{
                        msg0: '祖母绿',
                        msg1: '珍珠'
                    }
                },
                methods:{ },
                components:{
                    Father:{
                        template:'#father',
                        props:{
                            givevals1:{
                                type: String  
                            }
                        },
                        data(){
                            return{}
                        },
                        methods:{ },
                        components:{
                            Son:{
                                template:'#son',
                                props:{
                                    givevals2:{
                                      type: String  
                                    }
                                },
                                data(){
                                    return{}
                                },
                                methods:{}
                            }
                        }
                    }
                }
            }
        }
    })
</script>

在这里插入图片描述

8.$listeners: 孙子传值爷爷

步骤:

  • 孙子组件自定义事件传值,传给上级组件
  • 在父组件中 ,给调用孙子组件的位置 添加v-on="$listeners"
  • 爷爷组件中,在调用父亲组件的位置,监听孙子组件的自定义事件,取值
    示例:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .grandfa{
            width: 500px;
            height: 400px;
            background-color: rgb(246, 255, 0);
        }
        .father{
            width: 480px;
            height: 240px;
            background-color: aqua;
        }
        .son{
            width: 450px;
            height: 100px;
            background-color: rgb(243, 95, 95);
        }
    </style>
</head>
<body>
    <div id="app">
        <Grandfa class="grandfa"></Grandfa>
    </div>
    <!-- 爷爷组件 -->
    <template id="grandfa">
        <div>
            <h1>爷爷组件</h1>
            <p>爷爷获取孙子的值:{{msg}}</p>
            <Father @to_grandfa="accept_son"></Father>
        </div> 
    </template>
    <!-- 父组件 -->
    <template id="father">
        <div  class="father">
            <h1>父组件</h1>
            <Son v-on="$listeners"></Son>
        </div>
    </template>
    <!-- 子组件 -->
    <template id="son">
        <div  class="son">
            <h1>孙子组件</h1>
            <p>孙子=>爷爷的值:{{ obj }}</p>
            <button @click="change">传值给爷爷</button>
        </div> 
    </template>
</body>
</html>
<script src="./lib//vue(1).js"></script>
<script>
    // 创建实例
    var vm = new Vue({
        el: '#app',
        data:{},
        methods: {},
        components: {
            Grandfa:{
                template:'#grandfa',
                data(){
                    return{
                        msg:{}
                    }
                },
                methods:{ 
                    accept_son(v){
                        this.msg = v;
                    }
                },
                components:{
                    Father:{
                        template:'#father',
                        props:{},
                        data(){
                            return{}
                        },
                        methods:{ },
                        components:{
                            Son:{
                                template:'#son',
                                props:{
                                },
                                data(){
                                    return{
                                        obj:{
                                            gift1:'养生茶',
                                            gift2:'太极拳谱'
                                        }
                                    }
                                },
                                methods:{
                                    change(){
                                        this.$emit('to_grandfa',this.obj)
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    })
</script>

在这里插入图片描述

9. bus传值 (※)

使用方法:(适用于 多层组件传值)
1、在main.js中全局挂载bus
2、在要传值的组件中,使用this.bus. e m i t ( ′ 自定义事 件 ′ ,要传递的值 ) 3 、在需要接收传值的组件中, m o u n t e d 钩子函数中,使用 t h i s . b u s . emit('自定义事件',要传递的值) 3、在需要接收传值的组件中,mounted钩子函数中,使用this.bus. emit(自定义事,要传递的值)3、在需要接收传值的组件中,mounted钩子函数中,使用this.bus.on(‘自定义事件名’,(v)=>{v}) 接受传递的数据
以6层组件嵌套为例:
我们先自定义6个组件完成嵌套:
A.vue

<template>
  <div class="abox">
    <h1>A组件,最外层的</h1>
    <B></B>
  </div>
</template>
<script>
import B from "../components/B";
export default {
  props: {},
  data() {
    return {};
  },
  methods: {},
  components: {
    B,
  },
};
</script>
<style scoped lang="less">
.abox {
  width: 100%;
  padding: 20px;
  background-color: #e6ddcd;
  color: white;
}
</style>

B.vue

<template>
  <div class="bbox">
    <h2>B组件</h2>
    <C></C>
  </div>
</template>
<script>
import C from "./C";
export default {
  props: {},
  data() {
    return {};
  },
  methods: {},
  components: {
    C,
  },
};
</script>
<style scoped lang="less">
.bbox {
  width: 80%;
  margin: 20px auto;
  padding: 20px;
  color: white;
  background-color: #c9b486;
}
</style>

C.vue

<template>
  <div class="cbox">
    <h3>C组件</h3>

    <D></D>
  </div>
</template>
<script>
import D from "./D";
export default {
  props: {},
  data() {
    return {};
  },
  methods: {},
  components: {
    D,
  }
};
</script>
<style scoped lang="less">
.cbox {
  width: 80%;
  margin: 20px auto;
  padding: 20px;
  background-color: #2b6363;
}
</style>

D.vue

<template>
  <div class="dbox">
    <h4>D组件</h4>
    <E></E>
    <F></F>
  </div>
</template>
<script>
import F from "./F";
import E from "./E";
export default {
  props: {},
  data() {
    return {};
  },
  methods: {},
  components: {
    F,
    E,
  },
};
</script>
<style scoped lang="less">
.dbox {
  width: 80%;
  margin: 20px auto;
  padding: 20px;
  color: white;
  background-color: #153547;
}
</style>

E.vue

<template>
  <div class="ebox">
    <h5>E组件</h5>
    
  </div>
</template>
<script>
export default {
  props: {},
  data() {
    return {
      egift: "E孝敬的茅台",
    };
  },
  methods: {},
  components: {},
};
</script>
<style scoped lang="less">
.ebox {
  width: 80%;
  margin: 20px auto;
  padding: 20px;
  color: white;
  background-color: #071632;
}
</style>

F.vue

<template>
  <div class="ebox">
    <h5>F组件</h5>
  </div>
</template>
<script>
export default {
  props: {},
  data() {
    return {};
  },
  methods: {},
  components: {},
  mounted() {
   
  },
};
</script>
<style scoped lang="less">
.ebox {
  width: 80%;
  margin: 20px auto;
  padding: 20px;
  color: white;
  background-color: #071632;
}
</style>

1、在main.js中全局挂载bus
main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

//1、把bus属性 挂载在vue原型对象上
Vue.prototype.bus = new Vue();

new Vue({
  router,
  render: function (h) { return h(App) }
}).$mount('#app')

2、在需要传递数据的组件中使用bus触发自定义事件
此处以E.vue为例

<template>
  <div class="ebox">
    <h5>E组件</h5>
    <button @click="EChange">E要孝敬大家了</button>
  </div>
</template>

<script>
export default {
  props: {},
  data() {
    return {
      egift: "E孝敬的茅台",
    };
  },
  methods: {
    EChange() {
      this.bus.$emit("ESend", this.egift);
    },
  },

  components: {},
};
</script>

<style scoped lang="less">
.ebox {
  width: 80%;
  margin: 20px auto;
  padding: 20px;
  color: white;
  background-color: #071632;
}
</style>

3、需要接收的组件接收,使用this.bus.$on(‘自定义事件名’,()=>{v})
此处以A.vue组件为例

<template>
  <div class="abox">
    <h1>A组件,最外层的</h1>
    <B></B>
  </div>
</template>

<script>
import B from "../components/B";
export default {
  props: {},
  data() {
    return {};
  },
  methods: {},
  components: {
    B,
  },
  mounted() {
    this.bus.$on("ESend", (v) => {
      console.log("a接收E孝敬的:", v);
    });
  },
};
</script>

<style scoped lang="less">
.abox {
  width: 100%;
  padding: 20px;
  background-color: #e6ddcd;
  color: white;
}
</style>

在c组件,F组件中如法炮制,同样的写法。当我们触发E组件传值时,神奇的现象来了:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值