• Vue非父子组件之间的通信


    非父子组件的通信

    此篇讲解的是, 在学习状态管理之前, 非父子间通信的方案

    在开发中,我们构建了组件树之后,除了父子组件之间的通信之外,还会有非父子组件之间的通信

    这里我们主要讲两种方式

    • Provide/Inject

    • 全局事件总线

    1.Provide和Inject

    1.1基本使用

    Provide/Inject用于非父子组件之间共享数据

    • 比如有一些深度嵌套的组件,子组件想要获取父组件的部分内容
    • 在这种情况下,如果我们仍然将props沿着组件链逐级传递下去,就会非常的麻烦;

    对于这种情况下,我们可以使用 Provide 和 Inject

    • 无论层级结构有多深,父组件都可以作为其所有子组件的依赖提供者
    • 父组件有一个 provide 选项来提供数据;
    • 子组件有一个 inject 选项来开始使用这些数据;

    实际上,你可以将依赖注入看作是“long range props”,除了

    • 父组件不需要知道哪些子组件使用它 provide 的 property
    • 子组件不需要知道 inject 的 property 来自哪里

    我们开发一个下面这样的结构: 让App.vue提供一些数据给HomeContent.vue使用[外链图片转存失败,在这里插入图片描述

    在祖先组件中通过provide将数据传出, provide对应的是一个对象

    export default {
      components: {
        Home
      },
      // 通过provide将数据传出
    	provide() {
    		return {
    			name: this.name,
    			age: this.age,
    			height: this.height
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在后代元素中, 通过inject接收祖先传递的数据, inject对应的是一个数组

    export default {
      inject: ["name", "age", "height"]
    }
    
    • 1
    • 2
    • 3

    1.2处理响应式数据(了解)

    我们先来验证一个结果:如果我们修改了this.names的内容,那么使用length的子组件会不会是响应式的?

    <template>
      <div class="app">
        <home />
        <h2>{{ name }}h2>
        <button @click="btnClick">按钮button>
      div>
    template>
    
    <script>
      import Home from './Home.vue'
    
      export default {
        components: {
          Home
        },
        data() {
          return {
            name: "chenyq",
            age: 18,
            height: 1.88,
          }
        },
        // 通过provide将数据传出
        provide() {
          return {
            name: this.name,
            age: this.age,
            height: this.height
          }
        },
        methods: {
          btnClick() {
            this.name = "kaisa"
          }
        },
      }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    我们会发现对应的子组件中是没有反应的

    在这里插入图片描述

    这是因为当我们修改了names之后,之前在provide中引入的 this.name 本身并不是响应式

    那么怎么样可以让我们的数据变成响应式的呢?

    • 非常的简单,我们可以使用响应式的一些API来完成这些功能,比如说computed函数
    • 当然,这个computed是vue3的新特性,在后面我会专门讲解,这里大家可以先直接使用一下;
    import { computed } from 'vue'
    
    export default {
      components: {
        Home
      },
      data() {
        return {
          name: "chenyq",
          age: 18,
          height: 1.88,
        }
      },
      // 通过provide将数据传出
      provide() {
        return {
          name: computed(() => this.name),
          age: this.age,
          height: this.name
        }
      },
      methods: {
        btnClick() {
          this.name = "kaisa"
        }
      },
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    注意:我们在使用name的时候需要获取其中的value

    • 这是因为computed返回的是一个ref对象,需要取出其中的value来使用
    <template>
      <div class="home-content">
        <h2>名字: {{ name.value }}, 年龄: {{ age}}, 身高: {{ height}}h2>
      div>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.全局事件总线

    Vue3从实例中移除了 o n 、 on、 onoff 和 $once 方法,所以我们如果希望继续使用全局事件总线,要通过第三方的库

    • Vue3官方有推荐一些库,例如 mitt 或 tiny-emitter, 这两个库虽然不再维护, 但还是可以使用的;
    • 这里我们主要讲解一下 hy-event-store 的使用, 是前端大神coderwhy封装的他自己的库;

    首先,我们需要先安装这个库npm install hy-event-store

    其次,我们可以封装一个工具eventbus.js

    import { HyEventBus } from "hy-event-store";
    
    const eventBus = new HyEventBus()
    
    export default eventBus
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在项目中导入后可以使用它们

    • 我们在App.vue中监听事件;
    • 我们在Banner.vue中触发事件;

    Banner中触发事件:

    <template>
      <div class="home-content">
        <button @click="btnClick">按钮button>
      div>
    template>
    
    <script>
      import eventBus from './utils/event-bus'
    
      export default {
        methods: {
          btnClick() {
            console.log("myEvent事件被监听")
    				// 发送事件到事件总线上
            eventBus.emit("myEvent", "chenyq", 18, 1.88)
          }
        },
      }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    App中监听事件:

    <script>
      import eventBus from './utils/event-bus'
      import Home from './Home.vue'
    
      export default {
        components: {
          Home
        },
        created() {
    			// 监听事件总线上的事件
          eventBus.on("myEvent", (name, age, height) => {
            console.log(name, age, height)
          })
        },
      }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
  • 相关阅读:
    前端环境变量释义import.meta.env.xxx
    CentOS中安装常用环境
    JUC——CyclicBarrier
    人生的开始
    二进制中1的个数 C++实现
    C#两个表多条件关联写法
    软考成绩什么时候查?怎么查?能复查吗?
    【block作为函数参数的应用案例之一 Objective-C语言】
    新建一个flask项目
    Javaweb之javascript的详细解析
  • 原文地址:https://blog.csdn.net/m0_71485750/article/details/125881540