Evan's blog Evan's blog
首页
关于
  • 分类
  • 标签
  • 归档
  • H5&CSS3
  • JS
  • TS
  • Node
  • Webpack
  • Vue2
  • Vue3
  • 微信小程序
  • Andorid
  • Flutter
推荐
GitHub (opens new window)

conanan

真相只有一个
首页
关于
  • 分类
  • 标签
  • 归档
  • H5&CSS3
  • JS
  • TS
  • Node
  • Webpack
  • Vue2
  • Vue3
  • 微信小程序
  • Andorid
  • Flutter
推荐
GitHub (opens new window)
  • 基础

  • 组件

    • 父子组件通讯
    • 非父子组件通讯
      • Provide/Inject—依赖注入
        • 介绍
        • 注意
        • 示例
      • Mitt 全局事件总线
        • 安装
        • 封装 eventbus.js & constant.js
        • 方法
        • 示例
    • 插槽
    • 动态组件
    • 异步组件
    • 生命周期
    • 组件的v-model
  • 动画

  • Composition Api

  • 高级语法

  • Vue源码

  • VueCLI&Vite

  • VueRouter

  • Vuex

  • 项目

  • Vue3.x
  • 组件
xugaoyi
2022-01-30
目录

非父子组件通讯

# 非父子组件通讯

在开发中,我们构建了组件树之后,除了父子组件之间的通信之外,还会有非父子组件之间的通信,这里我们主要讲两种方式。

# Provide/Inject—依赖注入

# 介绍

比如有一些深度嵌套的组件,子孙组件想要获取爷父组件的部分内容。在这种情况下,如果我们仍然将props沿着组件链逐级传递下 去,就会非常的麻烦。对于这种情况下,我们可以使用 Provide 和 Inject:

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

# 注意

  • provide 函数绑定 this
  • computed 响应式

# 示例

App.vue

<template>
  <div>
    <home></home>
    <button @click="addName">+name</button>
  </div>
</template>

<script>
import Home from './Home.vue'
import { computed } from 'vue'

export default {
  components: {
    Home,
  },
  // provide 对象中的 this 为 undefined,
  // 为了绑定 Vue 实例,可以使用类似 data 函数一样的方式实现
  // provide: { name: 'why' },
  provide() {
    return {
      name: 'why',
      age: 18,
      // length 需要在 name 的长度变化时改变,可以使用计算属性,computed 返回的是 ref 对象,需要 .value 获取值
      length: computed(() => this.names.length), // ref对象 .value
    }
  },
  data() {
    return {
      names: ['abc', 'cba', 'nba'],
    }
  },
  methods: {
    addName() {
      this.names.push('why')
      console.log(this.names)
    },
  },
}
</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
38
39

Home.vue

<template>
  <div>
    <home-content></home-content>
  </div>
</template>

<script>
  import HomeContent from './HomeContent.vue';

  export default {
    components: {
      HomeContent
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

HomeContent.vue

<template>
  <div>
    HomeContent: {{name}} - {{age}} - {{length.value}}
  </div>
</template>

<script>
  export default {
    // 也不知道从哪注入的?是不是全局的???
    inject: ["name", "age", "length"],
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12

# Mitt 全局事件总线

替代Vue实例,其实可以获取到Vue实例,就是比较麻烦。

Vue3从实例中移除了 $on、$off 和 $once 方法,所以我们如果希望继续使用全局事件总线,要通过第三方的库: Vue3官方有推荐一些库,例如 mitt (opens new window)(推荐) 或 tiny-emitter (opens new window);

# 安装

 npm install mitt
1

# 封装 eventbus.js & constant.js

eventbus.js mitt 封装

import mitt from 'mitt'

// 可以返回多个对象
const emitter = mitt()
// export const emitter1 = mitt();
// export const emitter2 = mitt();
// export const emitter3 = mitt();

export default emitter
1
2
3
4
5
6
7
8
9

constant.js 事件名常量

export const WHY_EVENT = "why";
1

# 方法

  • emit

  • on

  • off:取消掉之前注册的函数监听

    // 取消 emitter 中所有监听
    emitter.all.clear()
    
    // 定义一个函数
    function onFoo() {}
    emitter.on('foo', onFoo) // 监听
    emitter.on('foo', onFoo) // 取消监听
    
    1
    2
    3
    4
    5
    6
    7

# 示例

App.vue

<template>
  <div>
    <home/>
    <about/>
  </div>
</template>

<script>
  import Home from './Home.vue';
  import About from './About.vue';

  export default {
    components: {
      Home,
      About
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

Home.vue

<template>
  <div>
    <home-content></home-content>
  </div>
</template>

<script>
  import HomeContent from './HomeContent.vue';

  export default {
    components: {
      HomeContent
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

HomeContent.vue

<template>
  <div>
  </div>
</template>

<script>
  import emitter from './utils/eventbus';

  export default {
    created() {
      emitter.on("why", (info) => {
        console.log("why:", info);
      });

      emitter.on("kobe", (info) => {
        console.log("kobe:", info);
      });

      emitter.on("*", (type, info) => {
        console.log("* listener:", type, info);
      })
    }
  }
</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

About.vue

<template>
  <div>
    <button @click="btnClick">按钮点击</button>
  </div>
</template>

<script>
  import emitter from './utils/eventbus';

  export default {
    methods: {
      btnClick() {
        console.log("about按钮的点击");
        emitter.emit("why", {name: "why", age: 18});
        // emitter.emit("kobe", {name: "kobe", age: 30});
      }
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
编辑 (opens new window)
上次更新: 2022/03/23, 17:55:39
父子组件通讯
插槽

← 父子组件通讯 插槽→

最近更新
01
重点
04-12
02
搭建项目
04-04
03
TS补充
03-30
更多文章>
Theme by Vdoing | Copyright © 2019-2022 conanan | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式