面试官问起EventBus,我轻笑一声,却让他大吃一惊

本文将深入探讨 Vue 组件间通信的多种方式,从基础到高级的手法一一详述,旨在展示对 Vue 通信机制的全面了解,并突出对 Vue 3 的熟练运用。

1. Props

Props 是最基础的父子组件通信方式,通过父组件向子组件传递数据。在定义 Props 时,最好指定数据类型,并进行必要的类型检查,以确保数据的稳定性。以下是一个基本的 Props 示例:

父组件

<code><<strong>template</strong>> <<strong>child</strong> :b="b"/> </<strong>template</strong>> <<strong>script</strong> setup> <strong>const</strong> b = <strong>ref</strong>(1) </<strong>script</strong>></code>

子组件

<code><<strong>template</strong>> <<strong>p</strong>>{{props.b}}</<strong>p</strong>> </<strong>template</strong>> <<strong>script</strong> setup> <strong>const</strong> props = <strong>defineProps</strong>({ b:{ type: <strong>Number</strong> } }) </<strong>script</strong>></code>

2. $emit 事件触发

$emit 主要用于子组件向父组件传递信息。父组件可以通过监听子组件的事件来响应。以下是一个简单的 $emit 示例:

父组件

<code><<strong>template</strong>> <<strong>child</strong> @test="test" /> </<strong>template</strong>> <<strong>script</strong> setup> <strong>const</strong> <strong>test</strong> = (a)=>{ console.<strong>log</strong>(a) } </<strong>script</strong>></code>

子组件

<code><<strong>script</strong> setup> <strong>const</strong> emits = <strong>defineEmits</strong>(['test']) <strong>emits</strong>('test','test emited') </<strong>script</strong>></code>

3. Ref 模板引用

Ref 可以获取子组件的实例或者虚拟 DOM。虽然可以直接修改子组件的值或者调用方法来实现通信,但这种方式破坏了单向数据流,不推荐使用。

父组件

<code><<strong>template</strong>> <<strong>child</strong> ref="child" /> </<strong>template</strong>> <<strong>script</strong> setup> <strong>const</strong> child=<strong>ref</strong>(null) <strong>onMounted</strong>(()=>{ console.<strong>log</strong>(child.value.a) child.value.<strong>test</strong>('2') console.<strong>log</strong>(child.value.a) }) </<strong>script</strong>></code>

子组件

<code><<strong>template</strong>> <<strong>p</strong>> {{ a }}</<strong>p</strong>> </<strong>template</strong>> <<strong>script</strong> setup> <strong>const</strong> a = <strong>ref</strong>(1) <strong>const</strong> <strong>test</strong> = (val)=>a.value=val <strong>defineExpose</strong>({a,test}) </<strong>script</strong>></code>

4. $parent 和 $root

在 Vue 2 和 Vue 3 的 Options API 中,可以使用 $parent 和 $root 来访问父组件和根组件。在 Vue 3 的组合式 API 中,可以通过 getCurrentInstance 来获取父组件和根组件。

<code><<strong>script</strong> setup> <strong>const</strong> {parent,root} = <strong>getCurrentInstance</strong>() </<strong>script</strong>></code>

5. attrs 和 listeners

attrs 和 listeners 本质上是 Props 和 $emit 的变种,在子组件中可以直接使用,主要用于组件库等场景。

6. provide 和 inject

provide 和 inject 提供了一种依赖注入的方式,类似于 React 的 Context。父组件通过 provide 提供值,子组件通过 inject 获取值。

7. Vuex 或者 Pinia

Vuex 和 Pinia 是官方推荐的状态管理库,适用于大型应用和状态较多的场景。

8. EventBus

EventBus 是一种观察者模式的实现,用于组件间的通信。你提到的实现方式基本正确,但也可以使用 JavaScript 原生的 CustomEvent 来实现。

8.1 一般实现

以下是一个基本的 EventBus 实现示例:

javascript<code><strong>class</strong> <strong>EventBus</strong> { events = <strong>new</strong> <strong>Map</strong>() <strong>on</strong>(name, cb) { <strong>if</strong> (this.events.<strong>has</strong>(name)) { this.events.<strong>get</strong>(name).<strong>add</strong>(cb) } <strong>else</strong> { <strong>const</strong> cbs = <strong>new</strong> <strong>Set</strong>([cb]) this.events.<strong>set</strong>(name, cbs) } } <strong>off</strong>(name, cb) { <strong>if</strong> (this.events.<strong>has</strong>(name)) { <strong>const</strong> cbs = this.events.<strong>get</strong>(name) cbs.<strong>delete</strong>(cb) <strong>if</strong> (cbs.size === 0) { this.events.<strong>delete</strong>(name) } } } <strong>emit</strong>(name, data) { <strong>if</strong> (this.events.<strong>has</strong>(name)) { <strong>const</strong> cbs = this.events.<strong>get</strong>(name) cbs.<strong>forEach</strong>(cb => <strong>cb</strong>(data)) } } <strong>clear</strong>() { this.events.<strong>clear</strong>() } }</code>

8.2 我的答案

你提到的使用原生的 CustomEvent 也是一种简洁有效的方式来实现 EventBus,具有良好的兼容性和易用性。

javascript<code><em>// 触发事件</em> <strong>const</strong> evt = <strong>new</strong> <strong>CustomEvent</strong>('name', {detail:'事件携带的data'}) document.body.<strong>dispatchEvent</strong>(evt) <em>// 监听事件</em> document.body.<strong>addEventListener</strong>('name',({detail})=>{console.<strong>log</strong>(detail)})</code>
© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容