vue源码-vue组件通信方式

Posted suwu150

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue源码-vue组件通信方式相关的知识,希望对你有一定的参考价值。

vue源码(二)-vue组件通信方式

一、组件化

组件化开发能够提高开发效率,方便重复使用简化调试步骤,提升项目的可维护性,便于多人系统开发

二、通信方式

1.父组件->子组件
1.1通过属性props进行传递

子组件进行定义一个字段msg接受父组件传递的参数

<template>
    <div class="hello">
        <h3> msg </h3>
    </div>
</template>

<script>
    export default 
      name: 'HelloWorld',
      props: 
        msg: String
      
    
</script>

<style scoped>
    h3 
        margin: 40px 0 0;
    
</style>

上述代码中,通过对props中msg的限定,进行接收有父组件传递下来的内容,然后在模版文件中通过插槽表达式进行使用。

<HelloWorld msg="用于prop传递参数给子组件"/> // 父组件通过msg进行传递参数
1.2vm.$attrs
  • 只读

    包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (classstyle 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (classstyle 除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。

<template>
    <div class="hello">
        <p>$attrs.foo </p>
    </div>
</template>

<script>
    export default 
      name: 'HelloWorld'
    
</script>

<style scoped>
    h3 
        margin: 40px 0 0;
    
</style>

上述代码,通过$attrs属性进行获取由父组件传递的参数foo,这种方式用于获取在子组件中props中没有声明的属性,在父组件中使用和1.1使用方式一致

<HelloWorld foo="测试$attrs.foo"/> // 父组件通过foo进行传递参数
1.3 vm.$refs
  • 只读

    一个对象,持有注册过 ref 特性 的所有 DOM 元素和组件实例。通过给子组件添加ref的形式进行传递数据

    如下所示:

    <template>
        <div class="hello">
            <p> age </p>
        </div>
    </template>
    <script>
        export default 
          name: 'HelloWorld',
          data: () => 
            return 
              age: '30'
            
          
        
    </script>
    <style scoped>
        h3 
            margin: 40px 0 0;
        
    </style>
    

子组件中有数据age,我们能够在父组件中通过this.$refs.hw.age = '18'的方式进行修改age属性值

1.4 vm.$children-子元素
  • 只读

    当前实例的直接子组件。**需要注意 $children 并不保证顺序,也不是响应式的。**如果你发现自己正在尝试使用 $children 来进行数据绑定,考虑使用一个数组配合 v-for 来生成子组件,并且使用 Array 作为真正的来源。

与1.3同样的子组件,在父组件通信时,只需要使用this.$children[0].age = '20';方式进行处理age的值即可

2.子组件->父组件通信

通过注册自定义事件监听的方式进行传递,通过 @click="$emit(‘clickDiv’)"进行派发事件,然后父组件处理的方式

<template>
    <div class="hello" @click="$emit('clickDiv')">
        <h3> msg </h3>
    </div>
</template>

<script>
    export default 
      name: 'HelloWorld',
      props: 
        msg: String
      ,
      data: () => 
        return 
          age: '30'
        
      
    
</script>

<style scoped>
    h3 
        margin: 40px 0 0;
    
</style>

父组件中需要对事件进行监听

  <div id="app">
    <HelloWorld
            msg="用于prop传递参数给子组件"
            foo="测试$attrs.foo"
            ref="hw"
            @clickDiv="onMyClick"
    />


其中onMyClick是父组件中方法,用于处理clickDiv传递的数据

3.兄弟之间通信:通过共同的祖辈组件通信

一般通过$parent$root进行处理,利用组件的生命周期进行监听事件,然后进行处理兄弟节点传递的数据

在每个需要监听的兄弟节点中添加下面监听事件

      created() 
        // 监听事件
        this.$parent.$on('hiBrother', () => 
          console.log('来自兄弟的问候', 'HelloWorld');
        );
      ,

接着在需要通过兄弟节点的地方进行调用如下代码:

this.$parent.$emit('hiBrother');

通过上述方式,就能够实现兄弟之间的通信

4.祖先和后代之间

由于嵌套层级过多,传递props不切合实际,可使用provide/inject API完成该任务

provide / inject:

​ 这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。如果你熟悉 React,这与 React 的上下文特性context很相似。

provide 选项应该是一个对象或返回一个对象的函数。该对象包含可注入其子孙的属性。在该对象中你可以使用 ES2015 Symbols 作为 key,但是只在原生支持 SymbolReflect.ownKeys 的环境下可工作。

inject 选项应该是:

  • 一个字符串数组,或
  • 一个对象,对象的 key 是本地的绑定名,value 是:
    • 在可用的注入内容中搜索用的 key (字符串或 Symbol),或
    • 一个对象,该对象的:
      • from 属性是在可用的注入内容中搜索用的 key (字符串或 Symbol)
      • default 属性是降级情况下使用的 value

在父组件进行提供值:

// ancestor
  provide()
    return 
      provideFoo: '测试provide/inject传递信息'
    
  ,

在子组件中进行使用注入值:

// descendant
inject: 
  provideFoo:  default: '这里设置默认值' 
,
// 或者使用数组形式
inject: ['provideFoo']
5.任意两个组件之间:事件总线或vuex
  • 事件总线:创建一个公共类负责事件派发、监听和回调管理
// EventEmit:事件派发、监听和回调管理
export default class EventEmit 
  constructor() 
    this.callbacks = ;
  
  $on(name, fn) 
    this.callbacks[name] = this.callbacks[name] || [];
    this.callbacks[name].push(fn);
  
  $emit(name, args) 
    if (this.callbacks[name]) 
      // 存在 遍历所有callback
      this.callbacks[name].forEach(cb => cb(args));
    
  


上述代码,使用$on进行注册全局监听事件、使用$emit进行通知全局处理事件.

当然我们需要将这个公共处理事件类挂在Vue原型上:

import Vue from "vue";
import App from "./App.vue";
import EventEmit from './utils/eventEmit';

// main.js
// 事件总线方式,挂载到Vue中
Vue.prototype.$eventEmit = new EventEmit();

new Vue(
  data: 
    bar: 'bar'
  ,
  render: h => h(App),
).$mount("#app");

在需要使用监听的地方进行添加监听

// 创建事件总线
this.$eventEmit.$on('fromHelloWorld', (value) => 
   alert('监听到由hello world组件传递来的数据:' + value);
);

在传递触发的组件中进行触发

// 派发事件,在HelloWorldEmit.vue组件中监听
this.$eventEmit.$emit('fromHelloWorld', '传递给HelloWorldEmit.vue的数据');
        

触发的同时,通过第二个参数进行传值。

以上就是组件之间通信的各种方式。

以上是关于vue源码-vue组件通信方式的主要内容,如果未能解决你的问题,请参考以下文章

vue2组件通信之$parent/$root

vue 提供注入 provideinject 深层嵌套通信

vue组件通信

vue组件通信

vue3源码分析——实现组件通信provide,inject

vue3源码分析——实现组件通信provide,inject