前端基础之《Vue(14)—组件通信》

一、什么是组件通信

1、通信是组件或模块之间的数据交互。

2、组件多重通信就形成了数据流,数据流管理的优劣决定了产品能否上线,返工是否频繁的问题。

3、Vue中有哪些常见的通信方案?

组件树的概念:

在Vue中,组件树(Component Tree)指的是一个由多个嵌套的Vue组件组成的层级结构。每个组件可以是另一个组件的子组件,这样层层嵌套形成一棵树。这种结构允许开发者构建复杂和可重用的用户界面。

(1)父子组件通信

父传子使用自定义属性(使用props接收),子传父使用自定义事件(使用$emit)。

(2)状态提升

状态就是数据的意思。

当兄弟组件之间需要共享数据时,我们通常的做法是把这个数据定义在它们的共同的父组件中,再通过自定义属性实现数据共享。

(3)provide/inject通信

这是一种在组件树间自上而下的一种数据通信方案。

也就是说,只能从父级组件中向后代组件传递。

是Vue提供的两个内置选项,可以对象写法,也可以function写法。

需要注意的是,当provide提供动态数据(声明式变量)时,动态数据发生变化,后代组件们不会自动更新,这是为什么呢?

因为生命周期流程中,是在beforeCreate()和created()之间,inject注入provide数据。

所以下面在例子代码里,更新父组件中的provide数据,子组件不会更新!!!

(4)ref通信

ref是Vue内置的一个属性,就像id、class一样,每一个HTML元素或组件都有这个属性。

ref作用在HTML元素上,得到DOM实例,ref作用在组件上得到组件实例。

使用ref访问组件实例,可以进一步访问组件中的数据和方法。

ref是一种快捷的DOM访问方式,当然ref也可以作用在组件上得到组件实例对象。这些ref得到的DOM实例或组件实例,使用this.$refs来访问它们。

ref尽量少用,除非某些难搞的需求。

(5)slot插槽通信

借助于<slot>组件实现从子组件向父组件传递数据。

借助this.$slots访问父组件中的插槽实例。

(6)parent/children通信

借助parent/children这两个API,可以实现在任一组件中访问组件树中的其它任意组件实例。可以做到在组件中随意穿梭。

(7)attrs/listeners通信

借助$attrs可以访问父组件传递过来的自定义属性(除了class和style外)。

借助$listeners可以访问父组件给的自定义事件。

在某些场景下,attrs/listeners可以替代props/$emit()这种通用的通信方式。

(8)事件总线

借助Vue内置的事件系统。(on/emit/off/once)实现"订阅-发布"模式的通信。这种通信方式是一对多的,且与组件的层级无关。

(9)Vuex通信

这是Vue架构中终极的通信方案,也是Vue架构中用的最多的一种通信方式。

二、状态提升例子

有一个变量大哥点了加1,二哥点了减1。

html 复制代码
<html>
<head>
    <title>组件通信-状态提升</title>
    <style>
        
    </style>
</head>
<body>
    <div id="app">
        <comp-child-a :numa="num" @add="num+=$event"></comp-child-a>
        <hr>
        <comp-child-b :numb="num" @sub="num-=$event"></comp-child-b>
        <hr>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>

    <script>

        Vue.component('comp-child-a', {
            template: `
            <div>
                <div>大哥  {{numa}}</div>
                <button @click='$emit("add", 1)'>加1</button>
            </div>
            `,
            props: {
                numa: {type: Number, default: 0}
            }
        })

        Vue.component('comp-child-b', {
            template: `
            <div>
                <div>二哥  {{numb}}</div>
                <button @click='$emit("sub", 1)'>减1</button>
            </div>
            `,
            props: {
                numb: {type: Number, default: 0}
            }
        })

        const app = new Vue({
            // 变量定义在父组件中
            data() {
                return {
                    num: 1
                }
            }
        })
        app.$mount('#app')

    </script>

</body>
</html>

三、provide/inject例子

注意:provide提供声明式变量numf,如果在父组件中修改了app.num的值,子组件中不会改变!!!

html 复制代码
<html>
<head>
    <title>组件通信-provide/inject</title>
    <style>
        
    </style>
</head>
<body>
    <div id="app">
        <comp-child-c></comp-child-c>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>

    <script>

        Vue.component('comp-child-c', {
            template: `
            <div>
                <div>三哥 {{msg}} - {{numf}}</div>
                <span v-for='i in list' v-text='i'></span>
            </div>
            `,
            // 从组件树的上下文中注入provide的数据
            inject: ['msg','list','numf']
        })

        const app = new Vue({
            // 变量定义在父组件中
            data() {
                return {
                    num: 1
                }
            },
            // 从当前组件节点开始,向后代组件们传递数据
            // 工作中更推荐function写法,因为可以用this
            // provide: {
            //     msg: "你好",
            //     list: [1,2,3,4]
            // }
            provide() {
                return {
                    msg: '你好',
                    list: [1,2,3,4],
                    numf: this.num // 动态数据

                }
            }
        })
        app.$mount('#app')

    </script>

</body>
</html>

四、ref例子

html 复制代码
<html>
<head>
    <title>组件通信-ref</title>
    <style>
        
    </style>
</head>
<body>
    <div id="app">
        <div ref='box'>普通HTML标签</div>
        <comp-child-d ref='dd'></comp-child-d>
        <button @click='handle'>测试ref操作</button>
        
    </div>

    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>

    <script>

        Vue.component('comp-child-d', {
            template: `
            <div>
                <div>四哥  {{age}}</div>
            </div>
            `,
            data() {
                return {
                    age: 10
                }
            },
            methods: {
                changeAge(arg) {
                    this.age = arg || 10
                }
            }
        })

        const app = new Vue({
            // 变量定义在父组件中
            data() {
                return {
                    num: 1
                }
            },
            methods: {
                handle() {
                    console.log('---refs', this.$refs)
                    this.$refs.box.style.color = 'red'
                    this.$refs.dd.changeAge(20)
                }
            }
        })
        app.$mount('#app')

    </script>

</body>
</html>

点击按钮:

获取到DOM实例和组件实例:

相关推荐
阿黄学技术1 小时前
Vite简单介绍
前端·前端框架·vue
264玫瑰资源库2 小时前
网狐飞云娱乐三端源码深度实测:组件结构拆解与部署Bug复盘指南(附代码分析)
java·开发语言·前端·bug·娱乐
济南壹软网络科技-专注源码开发数十年!2 小时前
盲盒源码_盲盒系统_盲盒定制开发 盲盒搭建前端教程
开发语言·前端·uni-app·php
MaCa .BaKa2 小时前
36-校园反诈系统(小程序)
java·spring boot·mysql·小程序·vue·maven·uniapp
哟哟耶耶3 小时前
react-13react中外部css引入以及style内联样式(动态className与动态style)
前端·css·react.js
A_aspectJ3 小时前
【Bootstrap V4系列】学习入门教程之 组件-卡片(Card)高级用法
前端·学习·bootstrap
DT——3 小时前
ECMAScript 6(ES6):JavaScript 现代化的革命性升级
前端·javascript·ecmascript
qq_400552004 小时前
【React Hooks原理 - useCallback、useMemo】
前端·react.js·前端框架
互联网搬砖老肖4 小时前
深入理解 Web 架构:从基础到实践
前端·架构
来自星星的坤4 小时前
用 Tailwind CSS 优化你的 Vue 3 项目! ! !
前端·css·vue.js