Vue面试之组件通信的方式总结(下篇)

Vue面试之组件通信的方式总结

  • $ref
  • provide&inject
    • provide
    • inject
  • EventBus事件总线
  • vuex

        最近在整理一些前端面试中经常被问到的问题,分为vue相关、react相关、js相关、react相关等等专题,可持续关注后续内容,会不断进行整理~

        在Vue框架中,提供了多种组件通信方式:props父子组件传参、插槽传参、Event Bus方式、vuex方式传参等,之前已对前两种方式进行了总结,本文继续总结其余方法~

$ref

在Vue中很少会直接操作DOM,但是一般情况下会用ref和$ refs取某DOM结构,具体来说:利用ref给元素或子组件注册信息,则该信息就会被注册到父组件的$ refs对象上。
$refs是一个对象,包含已经注册过ref的所有子组件的内容

ref有三种用法:

  1. ref加在普通元素上,则通过this.$refs.xxx获取到的是dom元素;
<p id="p1" ref="p1">这是第一段p>
console.log(this.$refs.p1) // 就可以拿到p1对应的dom元素

ref用在普通元素上
2. ref加在子组件上,则通过this.$refs.xxx获取到的是组件,可拿到子组件的所有属性和方法,实现子组件向父组件通信;同时如果在使用子组件方法时传入参数,则可以实现父组件向子组件通信;

Vue面试之组件通信的方式总结(下篇)_第1张图片
上图展示了利用this.refs.xxx可以获取到子组件身上的所有属性和方法,从而实现子组件向父组件通信;
这里需要注意的一点是,$refs只有在子组件被渲染后才能拿到,使用时一定要确保子组件已经被渲染,否则拿到的只能是undefined
父组件利用子组件的submit方法,可在使用时传递参数,这样调用时,子组件就可以拿到传递过来的参数值,实现父组件向子组件的通信;


<Son ref="son">Son>
<button @click="finish">提交button>
// 父组件中 
finish() {
	this.$refs.son.submit('12')
	// 调用子组件中的submit方法,并将12作为参数传递
}
// 子组件中 
submit(params) {
	console.log('拿到了父组件传递过来的参数', params)
	// 可以拿到父组件传递过来的参数12
}
  1. 如果使用 v-for 渲染多个相同类型的子组件,$refs 将成为一个数组。

provide&inject

provideinject也可以用来进行跨层级组件通信,父组件通过provide提供数据或方法,而子孙组件通过inject拿到数据或方法;

provide

它有两种写法:

  1. 对象写法
    如果传递的数据是个‘死数据’(静态数据),则可以直接利用对象形式将其传递;
// Parent.vue
export default {
// provide对象写法,直接将数据进行传递
  provide: {
  	age: 13
  },
};
  1. 函数写法
// Parent.vue
export default {
  data() {
    return {
      list: [...], // 一些数据
    };
  },
  provide() {
  // provide函数写法,可以将动态数据传递
    return {
      list: this.list, // 提供属性
      submit: this.submit // 提供方法
    };
  },
  methods: {
    submit() {
      // 一些逻辑
    }
  }
};

inject

inject的写法也有两个:

  1. 数组写法
    如果不用给传递过来的数据重命名,可采用此方法(上例中的传递age)
// Child.vue
export default {
  inject: ['age'], // 数组形式
  mounted() {
    console.log(this.age); // 可以访问父组件提供的数据,12
  },
};
  1. 对象形式
    如果需要对传递过来的数据重命名,可采用对象形式(上例中传递submit与list)
// Child.vue
export default {
  inject: {
    parentList: 'list',
    parentSubmit: 'submit'
  },
  mounted() {
    console.log(this.parentList); // 可以访问父组件提供的数据
    this.parentSubmit(); // 可以调用父组件提供的方法
  },
};

需要注意的是,provide 提供的数据不是响应式的,这意味着如果提供的数据发生变化,子组件不会自动重新渲染。如果需要响应式数据,可以使用 Vue 的实例或 Vuex 等状态管理工具。

EventBus事件总线

事件总线是一种简单而有效的组件通信方式,它通过一个中央的事件总线来传递消息,允许不同组件之间进行解耦合的通信。它属于** 订阅/发布模式实现的一种方式,通常可以通过创建一个全局的Vue实例**作为事件总线。分为如下几个步骤:

  1. 创建事件总线实例
// eventBus.js
import Vue from 'vue';
export const EventBus = new Vue();
  1. 在父组件中发送事件,使用$emit
// 父组件
import { EventBus } from '@/utils/eventBus.js'
showDetails (val) {
      EventBus.$emit('message-event', '12')
      // 发送message-event事件,传递12这个数据
    },
  1. 在子组件中接收事件,使用$on
// 子组件
import { EventBus } from '@/utils/eventBus.js'
mounted() {
  EventBus.$on('message-event', this.doSomething)
   // 当message-event发生改变时,就会触发doSomething方法
},
methods() {
 doSomething(params) {
    console.log('被事件触发了此方法~')
    console.log('并能接收到了数据', params)
  }
}

事件总线
4. 为防止内存泄露,一般在组件卸载时需要解绑事件总线,使用$off

// 子组件
 beforeDestroy() {
    EventBus.$off('message-event', this.doSomething);
    // 解绑message-event事件
  },

    在解绑事件时,$off 方法的第二个参数是一个可选的回调函数。如果在 $on 时使用了具名的回调函数,可以在 $off 时只传递回调函数而省略事件名称,这样就能够更精确地解绑特定的回调函数,如:

beforeDestroy() {
  EventBus.$off(this.doSomething);
},
  1. 在大型应用中,为了防止命名冲突,可以考虑使用命名空间来管理事件总线。可以在 EventBus.js 中为每个模块或组件创建一个子实例,以确保事件名称的唯一性。
// EventBus.js
import Vue from 'vue';
export const ParentEventBus = new Vue();
export const ChildEventBus = new Vue();
// 父组件
import { ParentEventBus } from '@/utils/eventBus.js'

注意:
    尽量避免滥用事件总线,特别是在大型应用中。对于父子组件通信或兄弟组件通信,更推荐使用 props 和 $emit;
    在多人协作或大型项目中,可能会使用更为复杂的状态管理工具(例如 Vuex)来代替事件总线;

vuex

该方式在以往文章中已经进行了详细的讲述,请移步Vue2教程详解七(Vuex3)

你可能感兴趣的:(前端面试,vue.js,面试,前端)