Vue中组件通信

前言

  当传递数据类型为引用数据类型:数组、方法、对象时,传递的是它们的引用地址,接收到的组件同样可以对其堆区数据进行操作

  父组件传递给子组件的,实际上只是一个引用地址,当子组件修改这个对象时,是真的修改了在堆空间中保存的数值,当然父组件中的值也会发生变化,但是引用地址没有进行修改,所以并没有报错。

注意:基本数据类型数据存放在栈区;引用数据类型地址名存放在栈区,数据存放在堆区。

  组件之间数据传输。
template中用div包裹html元素是因为,template中只能包裹一个盒子。

1 父传子

通过属性值props接收

  父传子:自定义属性 + props
  props用于接收来自父组件的数据。
  父传子:1)把数据当成子的自定义属性 2)在子对象中接收。
  子组件需要在父组件中注册。

<template>
  <div>
    <son :str="str" ></son>
  </div>
</template> 
     <script>
        import Son from "./Son";
        export default {
            name:'Father'
            data() {
                 return {
                   str: "给子组件传值"
                 }
            },
            components:{
                Son// 把Son组件对象注册到了Father组件中
            }
        }
     </script>
     //子组件接收后,可以当作自身data用
     <script>
        export default {
            name:'Son'
            props:{
                abc:String, //写法1:期待父给我传递的类型是String类型
                title:{     //写法2:
                    type:String,   // 期待父给我传递的类型是String类型
                    // required:true  // 父要使用子组件,必须要传title  不传就报错
                    default:"我是一个默认值"  //如果没传title指定默认值
                },
            }
            props:["title","abc"]//写法3:传啥 要啥 不在乎数据类型
        }
     </script>

2 子传父

通过事件传值 $emit

  子传父:自定义事件 + $emit
  同样需要在父组件中注册。

    <template id="father">
        <div>
            <h3>Father组件-------------{{fatherData}}------{{res}}</h3>
            <!-- @click 不是点击事件  -->
            <Son @clic="g"></Son>
            <!-- 不一定是点击事件  只是个名字 除非写了点击方法 -->
            <!-- @click自定义事件  事件名是click 点击时不会发生 自定义事件想让它发生,必须写代码-->
            <!-- 如果这个自定义事件发生,会调用g -->
        </div>
    </template>
        let Son = { 
            template:"#son",
            // 给son模板中提供方法的
            data(){
                return{
                    msg:"son中的数据"
                }
            },
            methods:{
                k(){
                    // 写代码 触发Son身上的自定义事件
                    this.$emit("click",this.msg)//当前组件实例 前者是事件,后者是数据
                }
            }
        }
  // 1)定义Father组件
        let Father = { 
            template:"#father",
            data(){
                return{
                    fatherData:"Father组件中的数据",
                    res:""
                }
            },
            // 给模板提供方法
            methods:{
                g(value){
                    console.log("g....",value);
                    this.res = value;
                }
            },
            // 把Son组件对象注册到了Father组件中
            components:{
                Son
            }
        }

3 处理边界情况(组件通信方案)

以下内容子组件据需注册到父组件中。

    <div id="app">
        <h1>{{msg}}</h1>
        <hr>
        <compa></compa>
    </div>

3.1 $root(获得根组件实例)

  在每个 new Vue 实例的子组件(在根实例中注册的)中,其根实例可以通过 $root property 进行访问。

  this.$root 可以得到根组件实例在这里插入图片描述

        let compa = {
            template: `
                <h1>compa组件------<button @click="fn">点我</button></h1>
            `,
            methods: {
                fn() {
                    // 在一个子组件中,可以通过$root,来获取根组件实例
                    console.log(this.$root);
                    console.log(this.$root.msg);
                    this.$root.f1()
                    // 表示修改根组件中的数据
                    this.$root.msg = "hi vue"
                }
            }
        }
        var vm = new Vue({
            el: '#app',
            data: {
                msg: "hello vue"
            },
            methods: {
                f1() {
                    console.log("f1.....");
                }
            },
            components: {
                compa
            },
        })

3.2 $parent(获得父组件实例)

  this.$parent 得到父组件实例在这里插入图片描述

        console.log(this.$parent);
        console.log(this.$parent.a);
        this.$parent.gn()

3.3 $children(获得子组件实例)

  this.$children 得到子组件实例
  得到的是一个数组,原因是子可以有多个。

        console.log(this.$children);
        console.log(this.$children[0]);
        console.log(this.$children[0].a);
        this.$children[0].kn()

3.4 $refs(获得子组件实例)

  this.$refs.xxx获得ref为xxx的子组件实例
  如果把ref写在普通的标签上,和id一样,是为了获取这个DOM元素

        <input type="text" ref="ipt" value="123">

  如果把ref写在一个组件上,是为了获取这个组件实例(赋予ID引用)

        <compa ref="a"></compa>

  这样在任意地方通过this.$refs.xxx获得ref为xxx的子组件的实例

            mounted(){
                // 得到a组件的实例
                console.log(this.$refs.a);
                console.log(this.$refs.a.number);
                this.$refs.a.kn()
                
                console.log(this.$refs.b.value);
            },

3.5 provide & inject依赖注入

  作用:可实现跨组件传值,数据的流只能是向下传递

  provide : 必须在分级组件(不一定是app.vue)进行使用,用来给后代组件注入依赖(属性或方法)。
  inject : 必须在子组件进行使用,用来获取根组件定义的跨组件传递的数据。

  provide在父中提供数据,在子子孙孙组件中都可以使用数据。
  可以实现跨级传输数据

        var app = new Vue({
            el: '#app',
            data: {
                username:"wangcai"
            },
            methods:{
            },
            // 在父中提供数据,在子子孙孙中可以消费数据
            provide(){               //作为方法使用
                return {
                    username:this.username
                }
            },
            // provide:{               //作为对象使用
              
            //         username:this.username
                
            // },
            components:{
                compa
            }
        })

  子或孙组件:

        let compb = {
            inject:["username"],       //接收数组
            // inject:{                //接收对象
            //     username:{
            //         default:'默认值' //指定默认值
            //     }
            // },
            template:`
                <h1>compb组件----------------{{username}}</h1>
            `,
        }

3.6 $attrs

  当一个组件中没有声明任何 prop 时,this.$attrs 可以获取到所有父作用域的属性绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传给其内部组件 —— 在创建高级别的组件时非常有用。

 props:["a","b","c"],
 $attrs  props可以接收数据,
 $attrs可以接收所有的数据
 并没有使用props接收a b c 但是$attrs中已经接收完毕
        <son :a="1" :b="2" :c="3"></son>
        let grandSon = {
            template:`
                <div>--------- grandSon组件----{{data}}-----</div>
            `,
            props:["data"],
        }
        let son = {                                  //$attrs方法
            template:`                                
                <div>--------- Son组件 ---------<grandSon :data="$attrs" /></div>
            `,
            // template:`                             props方法
            //     <div>--------- Son组件 ---------<grandSon :a="a" :b="b" :c="c" /></div>
            // `,
            components:{
                grandSon
            }
        }

3.7 $listeners

  v-on:click="xx" 绑定点击事件
  v-on=$listeners 绑定多个自定义事件

        <!-- @f1="f1" @f2="f2" @f3="f3" 在son组件上绑定三个自定义事件 -->
        <son @f1="f1" @f2="f2" @f3="f3"></son>
        
        let grandSon = {
            template:`
                <div>--------- grandSon组件----<button @click="kn">触发</button>-----</div>
            `,
            // props:["fn"],
            methods:{
                kn(){
                    // this.fn.f1()
                    this.$listeners.f3()//接收 或者触发方法
                }
            }
        }
        let son = {// <grandSon v-on="$listeners" />    v-on="$listeners"在grandSon组件上绑定了三个自定义事件
            template:`
                <div>--------- Son组件 ---------<grandSon v-on="$listeners" /></div>
                //注释<div>--------- Son组件 ---------<grandSon :fn="$listeners" /></div>
            `,
            mounted(){
                // console.log(this.$listeners);
            },
            components:{
                grandSon
            }
        }

3.8 event-bus(时间总线)

        事件总线:
            new一个Vue,可以创建一个根实例,也可以创建一条事件总线。

        在事件总线上有一个机制,叫发布订阅:
            发布:在合适的时机就可以发布    $emit()
            订阅:订阅某个公众号   $on()

        其实事件绑定也是发布订阅:
            <button onclick="alert(6666)">登录</button>

            事件绑定:订阅
            当点击按钮时:发布
        // 创建事件总线  使用一个空的 Vue 实例作为中央事件总线
        let eventBus = new Vue();
        
========根组件中发布meassge
        methods:{
            fn(){
                eventBus.$emit("meassge","hello 事件总线");
            }
        },
========其他组件中订阅meassge
        mounted(){//生命周期中获取
            eventBus.$on("meassge",function(msg){
                console.log("message这个事发生了...",msg);
            })
        },

3.9 sync(修饰props)

  sync对 props 起到了一种修饰的作用,使用 .sync 进行修饰的 props 意味子组件有修改它的意图,这种情况下它只起到一个标注性作用,有它没它都不会影响逻辑。

  :xxx="xxx" @update:xxx="fn" 可以写成:xxx.sync="xxx",减少代码量
  同时也不用在根实例methods中写

<body>
    <div id="app">
        <!-- @update:username="fn"  自定义事件 -->
        <!-- 事件名是:update:username -->
        <!-- <custom-input :username="username" @update:username="fn"></custom-input> -->
        <!-- 修饰符sync  可以对上面的代码进行简写 -->
        <custom-input :username.sync="username" ></custom-input>
        <hr>
        <h1>{{username}}</h1>
    </div>

    <script>
        Vue.component("custom-input",{
            template:`
                <input type="text" :value="username" @change="$emit('update:username',$event.target.value)" />
            `,
            props:["username"]
        })
        var app = new Vue({
            el: '#app',
            data: {
                username:"wangcai"
            },
            methods:{
                // fn(msg){
                //     this.username = msg;
                // }
            }
        })

    </script>
</body>

  文章参考:Vue 组件通信 12 种解决方案

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值