Vue组件通信

本文较为冗长,单条举多例进行说明。

一、父子通信:props,$emit。

1、props:
父组件

<template>
    <div>
        <div style="border: 1px solid #ddd;padding: 40px 0;">
            这是父组件
            <el-button type="primary" @click="changeChildCom()">改变子组件</el-button>
        </div>
        <ChildComponent :childPropsName="TestProps"></ChildComponent>
        <!--ChildComponent 为注册组件名称,childPropsName 名称自定义,子组件在接收时需要,TestProps 为父组件变量名称-->
    </div>
</template>
<script>
    import ChildComponent from '../test/child' //子组件引入
    export default {
        components:{
            ChildComponent //注册组件
        },
        name: "index",
        data(){
            return{
                TestProps:0
            }
        },
        methods:{
            changeChildCom(){ //改变父组件参数,子组件显示内容随之改变
                this.TestProps += 1
            }
        }
    };
</script>

子组件

<template>
    <div>这是子组件
        <el-button> {{childPropsName}}</el-button><!--childPropsName 为父组件在引用子组件时引用-->
    </div>
</template>

<script>
    export default {
        name: "child",
        props:{
            childPropsName:{
                type:Number,
                value:0
            }
        }
    };
</script>

注意父子组件的 childPropsName 用法

子组件需求父组件的某变量 TestProps,在父组件中引入注册并使用当前子组件,在使用时绑定一个子组件接收名称 childPropsName,子组件的 props 中再声明一次将要接收这个变量即可。

子组件显示内容依赖父组件参数TestProps,当父组件参数发生改变,会影响子组件显示内容。
在这里插入图片描述
2、$emit:
父组件

<template>
    <div>
        <div style="border: 1px solid #ddd;padding: 40px 0;">
            这是父组件{{TestParent}}
        </div>
        <ChildComponent @parentFunction="getchildData"></ChildComponent>
    </div>
</template>

<script>
    import ChildComponent from '../test/child'
    export default {
        components:{
            ChildComponent
        },
        name: "index",
        data(){
            return{
                TestParent:0
            }
        },
        methods:{
            getchildData(val){
                this.TestParent = val
            }
        }
    };
</script>
<template>
    <div>这是子组件
        <el-button type="error" @click="handleParent">改变父组件</el-button>
    </div>
</template>

<script>
    export default {
        name: "child",
        methods:{
            handleParent(){
                this.$emit('parentFunction',1)
            }
        }
    };
</script>

$emit是一个程序化的事件监听器,他可以通过v-on进行事件监听

在引入使用子组件时,在子组件上就通过 v-on或者 @ 绑定父组件的方法,在子组件通过$emit去调用这个方法,并将值通过传参的形势发送给父组件。

在这里插入图片描述
在这里插入图片描述

二、多组件嵌套关系的父组件、孙子组件传参:$attrs、 $listeners

当拥有一级与二级的层级嵌套关系的时候,props与$emit就可以适用了,但当有多级嵌套关系,父组件的孙子组件要想实现与父组件通信的时候,如果再使用props与 $emit就需要多次重复接收或发送,就太过冗余了。

Vue 2.4开始提供了 $attrs和 $listeners来解决这个问题,能够让父组件与孙子组件这种多层嵌套关系的组件进行参数传递。

关系:父组件 => 父组件引用子组件 => 子组件引用孙子组件

目的:父组件引用孙子组件数据,孙子组件使用父组件数据。

父组件

<template>
    <div>
        <div style="border: 1px solid #ddd;padding: 40px 0;">
            这是父组件{{messagec}}
        </div>
        <ChildComponent :messagec="messagec" @grandsonMethod="getGrandsonData"></ChildComponent>
    </div>
</template>

<script>
    import ChildComponent from '../test/child'
    export default {
        components:{
            ChildComponent
        },
        name: "index",
        data(){
            return{
                messagec:'123'
            }
        },
        methods:{
            getGrandsonData(val){
                console.log("这是来自孙子组件的数据:",val)
                this.messagec = val
            }
        }
    };
</script>

子组件

<template>
    <div>这是子组件
        <TextT v-bind="$attrs" v-on="$listeners"></TextT>
    </div>
</template>

<script>
    import TextT from './childT'
    export default {
        components:{
            TextT
        },
        name: "child",
    };
</script>

孙子组件

<template>
    <div>
    <div>这是孙子组件</div>
        <input type="text" v-model="$attrs.messagec" @input="commitData($attrs.messagec)" />
    </div>
</template>

<script>
    export default {
        name: "childT",
        methods:{
            commitData(val){
                this.$emit('grandsonMethod',val)
            }
        }
    };
</script>

子组件仅作为过渡桥梁的作用,通过 v-bind="$attrs" / v-on="$listeners" 建立引用关系,而父组件就会将所有的事件监听器指向子组件中引用的孙子组件,从而达到数据通信的作用。

注意:父传孙子:子组件使用 v-bind="$attrs" 孙子组件可以直接使用this.$attrs.父组件变量名去访问这个变量。

孙子调用父组件方法并传值:v-on="$listeners" 同样使用$emit。
在这里插入图片描述

在这里插入图片描述

三、prototype链式层级关系抓取内容: $root、 $parent、 $children、 $el

脚手架的项目开端,从入口文件中的new Vue开始
在这里插入图片描述
我们在App.vue的id为app的dom节点下开始了罪恶的一生,链式关系就从这儿开始。

目前用作讲解的例子关系

Vue根实例
------App.vue
|----------Head.vue
|
|
|----------Body.vue
|-------------|----Parent.vue
|---------------------|----Child.vue
|-----------------------------|-----Grandson.vue
|
|----------Foot.vue

最顶级,最外层级为Vue根实例,其次是App.vue组件,我们在App.vue组件下可能引入使用了类似头部,主体,脚注甚至更多的组件内容,也可能在这些组件下引入使用了再下级的组件,类似Body.vue中引入使用了父组件,父组件下引用了子组件,子组件下引用了孙子组件。不断的套娃。

1、$root,直接获取根实例

不论你嵌套层级有多深,$root可以直接获取到嵌套的最顶层根实例部分

我在以上嵌套关系的Grandson.vue(孙子组件)中打印了$root的内容,获取到一个Vue的实例化对象
在这里插入图片描述

可以看到这个对象下会有很多方法,在这个对象下,似乎看到了我们所需要的 $children, $el , $parent

在这里插入图片描述
根实例下的 $children 包含所有的嵌套层级关系。

2、$el 节点操作

在实际的操作过程中,移入 $el 时,发现页面上的根节点#App被选中
在这里插入图片描述
单独打印这个 $el,确实也得到了节点内容

在这里插入图片描述
既然我们已经选中了这个节点,那我们同样可以操作他。

this.$root.$el.style.display = 'none'

亲测有效。

在这里插入图片描述
3、$parent 当前嵌套的上一层关系

父组件

<template>
    <div>
        <div style="border: 1px solid #ddd;padding: 40px 0;">
            这是父组件{{parentData}}
        </div>
        <ChildComponent></ChildComponent>
    </div>
</template>

<script>
    import ChildComponent from '../test/child'
    export default {
        components:{
            ChildComponent
        },
        name: "index",
        data(){
            return{
                parentData:'123'
            }
        },
        methods:{
            parentMethod(val){
                this.parentData = val
            }
        }
    };
</script>

子组件

<template>
    <div>这是子组件
        <el-button @click="getParentData">获取父组件的数据</el-button>
        <el-button @click="useParentMethod">使用父组件的方法并传参</el-button>
    </div>
</template>

<script>
    export default {
        name: "child",
        methods:{
            getParentData(){
                alert(this.$parent.parentData)
            },
            useParentMethod(){
                this.$parent.parentMethod('456')
            },
        }
    };
</script>

页内效果
在这里插入图片描述

可以看到,以上为父组件引入了子组件,父组件定义了一个变量为parentData,初始值为123,并定义了事件parentMethod,事件中重新对parentData变量赋值为传递过来的参数。

通过this.$parent.变量名可以使用父类组件的变量,也可以直接操作这个变量。

通过this.$parent.方法名 可以使用父类组件的方法,在子组件中可以调用这个方法并传递参数。

点击获取 父类组件的数据按钮,触发弹窗,弹出父组件 parentData 的值123
在这里插入图片描述
点击 使用父组件的方法并传参 按钮,父组件的值改变为456
在这里插入图片描述
4、$parent 嵌套下的组件列

慎用
慎用
慎用

父组件

<template>
    <div>
        <div style="border: 1px solid #ddd;padding: 40px 0;">
            这是父组件<button @click="parentMethod">获取子组件兑现列表</button>
        </div>
        <ChildComponent></ChildComponent>
        <GrandComponent></GrandComponent>
    </div>
</template>

<script>
    import ChildComponent from '../test/child'
    import GrandComponent from '../test/childT'
    export default {
        components:{
            ChildComponent,
            GrandComponent
        },
        name: "index",
        methods:{
            parentMethod(){
                console.log(this.$children)
            }
        }
    };
</script>

子组件1

<template>
    <div>这是子组件1</div>
</template>
<script>
    export default {
        name: "child",
        data(){
            return{
                childData1:'123'
            }
        }
    };
</script>

子组件2

<template>
    <div>这是子组件2</div>
</template>
<script>
    export default {
        name: "child",
        data(){
            return{
                childData2:'2354'
            }
        }
    };
</script>

父组件引入了 子组件1子组件2,并定义了方法打印组件下的$children

在组件1 组件2中分别定义了一个变量。

点击触发后,结果为一个包含各自组件变量属性的列表。

在这里插入图片描述

可以通过this.$children[组件下标].变量 / this.$children[组件下标].方法 的形式去获取变量,调用方法。

至于慎用的原因:如果你使用的其他的ui框架,比如element ui 在组件中引用了框架中的某些元素样式,都有可能是框架中定义的组件,且使用$children,不利于后续的开发维护。

四、父传子孙,provide和inject 数据注入

Vue 2.2.0新增,这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在其上下游关系成立的时间里始终生效,只要嵌套的关系存在,下层组件就可以使用上层的数据/方法。

注意:下层组件只能对这个属性进行使用,并不能直接进行修改,当父组件向下注入参数发生改变,所有下层组件中使用的变量都会发生变化

嵌套关系:父组件(向下注入) ==》 父组件引用子组件 ==》子组件引用孙子组件

父组件

<template>
    <div>
        <div style="border: 1px solid #ddd;padding: 40px 0;">
            这是父组件
        </div>
        <ChildComponent></ChildComponent>
    </div>
</template>

<script>
    import ChildComponent from '../test/child'
    export default {
        components:{
            ChildComponent
        },
        provide:{
            parentCommon:'-----来自爸爸的爱'
        },
        name: "index"
    };
</script>

子组件

<template>
    <div>这是子组件{{parentCommon}}
        <GrandComponent></GrandComponent>
    </div>
</template>
<script>
    import GrandComponent from './childT'
    export default {
        name: "child",
        inject:['parentCommon'],
        components:{
            GrandComponent
        }
    };
</script>

孙子组件

<template>
    <div>这是孙子组件{{parentCommon}}</div>
</template>
<script>
    export default {
        name: "child",
        inject:['parentCommon']
    };
</script>

父组件使用provide 注入了名为 parentCommon 的变量,下层的子组件与孙子组件都可以通过inject和这个变量名称去共用这个变量。

得出结果:
在这里插入图片描述

五、子传父,$refs 收纳持有属性 ref 的DOM和实例

如果在引入使用组件时,组件上有注册使用ref属性,Vue组件就可以将持有这个属性的DOM 元素和组件实例收纳到当前Vue组件的$refs中。

适用与父子组件关系,作用是父组件使用子组件方法和变量

子组件

<template>
    <div>
        这是子组件
    </div>
</template>
<script>
    export default {
        name: "child",
        data(){
            return{
                childData:'这是子组件的数据'
            }
        },
        methods:{
            childMethod(){
                console.log('触发了子组件的方法')
            }
        }
    };
</script>

父组件

<template>
    <div>
        <div style="border: 1px solid #ddd;padding: 40px 0;">
            这是父组件
            <el-button @click="getChildData">获取子组件的数据</el-button>
        </div>
        <ChildComponent ref="childChildComponent"></ChildComponent>
    </div>
</template>

<script>
    import ChildComponent from '../test/child'
    export default {
        components:{
            ChildComponent
        },
        name: "index",
        methods:{
            getChildData(){
                //console.log(this.$refs.childChildComponent); //==>打印子组件Vue组件对象
                //this.$refs.childChildComponent.childData = '147258' // 触发后会修改子组件childData的值
                console.log(this.$refs.childChildComponent.childData); //==》打印出  这是子组件的数据

                this.$refs.childChildComponent.childMethod()  //触发子组件方法,并打印  触发了子组件的方法
            }
        }
    };
</script>

父组件在引入使用子组件时定义属性ref,属性值自定义,父组件可以通过 this.$refs.自定义属性值.子组件变量名 / this.$refs.自定义属性值.子组件方法名使用 / 修改 子组件的变量、调用子组件的方法。

六、Vuex 集中状态管理仓库

这个官网有更详细的说明,如果在项目中有跨多组件、多组件公用变量,且关系复杂的时候,就可以使用 Vuex

也有对其讲解升入的博主 博客供大家深入思考。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值