跳转到内容

BlueOS 应用开发,组件之间如何通信?

BlueOS 应用开发,同样采用组件树来构建,这能带来诸多好处:代码重用、逻辑分隔、 易于维护、高内聚低耦合、快速迭代、易于测试、高可扩展性等等,各类组件(父子、兄弟、爷孙、跨级等)交织在一起,就需要解决组件通信;本文旨在探讨,BlueOS 应用开发组件之间如何通信

在深入讨论之前,先总结整体建议:

  • 在父子组件间,推荐采用 props 向子组件传递数据,因为这种能满足诉求,而且方式简单、直接;通过调用 $broadcast() 完成向子组件传递事件,子组件通过 $on() 监听事件触发;
  • 在父子组件间,子组件可通过 $dispatch() 触发自定义事件,父组件通过 $on() 监控自定义事件的触发;子组件通过 $emit() 触发在节点上绑定的自定义事件,来执行父组件的方法;
  • 需要全局状态共享的通信需求,使用状态管理(如 Zustand )是更为合适的选择,可以有效降低组件间的耦合度和复杂性;详情参见下文全局状态管理
  • 如果是中小型应用,涉及到跨级组件通信,又不想引入第三方库,则可考虑通过自定义发布订阅模块完成。

组件通信方式

props 属性 / emits 事件

  • props 属性:类似于 Svelte、 React 中的 props,父组件可以通过 props 向子组件传递数据或方法。子组件可以通过 props 接收并使用这些数据或方法。
  • emits 事件:子组件可以通过触发事件来通知父组件或其他组件发生了某些操作或状态改变。通常是通过 $emit 方法触发自定义事件,并在父组件中通过监听这些事件来处理相应的逻辑。

这是 BlueOS 父子组件通信最常用、最基础的方案;但在兄弟、爷孙或其他关系组件之间使用这种方式,相对就麻烦许多,需要层层传递,不推荐采用。

在使用 props 传递数据时,需要注意以下几个事项:

  1. 命名方式:在子组件内部定义 props 时,应使用 camelCase(驼峰命名法)来命名。但在父组件中通过标签属性的方式传递数据时,应该使用 kebab-case(短横线分隔命名)的方式,即 propObject 在模板中应写作 prop-object

  2. 默认值:子组件在声明 props 时可以设置默认值。如果未传入值,则会使用这个默认值。但要注意的是,设置默认值时 props 必须以对象的形式定义,不能用数组的形式。

  3. 数据单向性:父子组件之间的 props 传递是单向的。即父组件的 props 更新,子组件会同步这些更新,但是不应该在子组件内部修改 props 的值,尤其当 props 的类型是数组或对象时,子组件内部的更改会影响父组件的状态,这可以导致不可预见的问题。

  4. 值的变更处理:若需要在子组件内部处理父组件传递的 prop 值,可以通过定义子组件自身的 data 属性或使用 $watch 来监听 props 的变化后处理。

全局状态管理

类似于 Svelte 自带的 Store 、 Vue 的 Pinia ,全局状态管理机制(如 ZustandRxJSVuex 或其他状态管理库),可以让不同组件之间共享状态。当一个组件修改了状态,其他组件可以通过订阅状态的方式获取到更新后的数据。

全局状态管理(Global State Management)在 BlueOS 应用开发中具有以下几个显著的优势:

  1. 集中管理状态:全局状态管理允许将应用中的共享状态集中存储和管理。这意味着你可以在一个单独的地方定义和更新应用的状态,而不需要在多个组件之间手动传递数据。这种集中管理可以显著简化组件间的数据流管理,使得代码更易于维护和调试。
  2. 跨组件通信:全局状态管理使得不同组件之间能够共享和同步状态,而无需通过繁琐的 props 传递或事件传递数据。当一个组件更新了状态,所有依赖于该状态的组件都可以及时获取到更新的数据,实现了组件间的解耦合和高效通信。
  3. 状态持久化:在某些场景下,全局状态管理可以方便地与本地存储结合,实现状态的持久化。例如,在用户刷新页面或重新打开应用时,可以从本地存储中恢复应用的状态,提供更好的用户体验。
  4. 方便的调试和测试: 由于状态集中管理,更容易在开发过程中对状态进行监视、调试和测试。开发者可以更方便地跟踪状态的变化,并且在开发工具中查看和修改状态,加快开发效率。
  5. 组件逻辑解耦:使用全局状态管理可以帮助降低组件之间的耦合度。组件只需关注自身的业务逻辑和展示,而不需要过多考虑数据的传递和共享,使得组件更加独立和可复用。

总之,全局状态管理是一种有效的解决方案,特别适用于中大型或复杂的项目,能够提升开发效率、代码的可维护性和应用的性能。BlueOS 官方目前尚未定制专属状态管理工具库,推荐采用开源工具库── Zustand 进行状态管理,它具有:体积小、性能好,简单易用等优势。

自定义发布-订阅

在 BlueOS 中实现跨级组件通信可以通过自定义发布订阅(Publish-Subscribe)机制来完成。以下是一个简单的示例,演示了如何使用发布订阅模式在不同级别的组件之间进行通信。

创建发布订阅模块

首先,创建一个简单的发布订阅模块,其中包括订阅、发布和取消订阅方法;用于全局事件的管理和触发。

pubsub.js
export default class EventBus {
constructor() {
this.events = {}
}
// 订阅事件
subscribe(eventName, callback) {
if (!this.events[eventName]) {
this.events[eventName] = []
}
this.events[eventName].push(callback)
}
// 发布事件
publish(eventName, ...args) {
if (this.events[eventName]) {
this.events[eventName].forEach((callback) => {
callback(...args)
})
}
}
// 取消订阅事件(可选)
unsubscribe(eventName, callback) {
if (this.events[eventName]) {
this.events[eventName] = this.events[eventName].filter(
(cb) => cb !== callback
)
}
}
}
// 创建一个全局的事件总线实例
export const eventBus = new EventBus()

跨级组件通信

主页面(父组件):引入 foobar 两个组件,并进行展示:

<template>
<div class="wrapper">
<text>{{ title }}</text>
<foo></foo>
<bar></bar>
</div>
</template>
<import name="foo" src="./../../components/Foo.ux"></import>
<import name="bar" src="./../../components/Bar.ux"></import>
<script>
export default {
data: {
title: '👏欢迎体验应用开发',
},
}
</script>
<style>
.wrapper {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: #ffe4c4;
}
</style>

子组件(Foo):监听来自 Bar 组件消息(msg-to-foo),点击按钮则触发消息(msg-to-bar):

<template>
<input
type="button"
value="Foo Component"
style="border: 1px solid #000000; padding: 5px; margin-top: 20px"
@click="onBtnClick" />
</template>
<script>
import { eventBus } from './../pubsub.js'
export default {
data: {
title: '🙌🏼 Hi, I am Foo',
},
onInit() {
eventBus.subscribe('msg-to-foo', this.handleMsgEvent)
},
onBtnClick() {
eventBus.publish('msg-to-bar', this.title)
},
handleMsgEvent(data) {
console.log('[@Foo] Received event from Bar Component:', data)
},
}
</script>

子组件(Bar):监听来自 Foo 组件消息(msg-to-bar),点击按钮则触发消息(msg-to-foo):

<template>
<input
type="button"
value="Bar Component"
style="border: 1px solid #000000; padding: 5px; margin-top: 20px"
@click="onBtnClick" />
</template>
<script>
import { eventBus } from './../pubsub.js'
export default {
data: {
title: '🤝 Hello, I am Bar',
},
onInit() {
eventBus.subscribe('msg-to-bar', this.handleMsgEvent)
},
onBtnClick() {
eventBus.publish('msg-to-foo', this.title)
},
handleMsgEvent(data) {
console.log('[@Bar] Received event from Foo Component:', data)
},
}
</script>

通过这种方式,父子组件之间不需要通过 props 或者事件传递来进行通信,而是通过事件总线实现了跨级别的组件通信,使得组件之间的耦合度更低,代码更加清晰和易于维护。但也存在一些潜在的缺点和考虑因素:

  • 全局事件管理:使用自定义的发布订阅模式可能会导致全局事件管理的复杂性增加。如果事件频繁使用,而没有清晰的命名和管理,可能会导致事件命名冲突或者难以追踪事件的来源和订阅情况。
  • 内存管理:应用开发者中,内存管理非常重要。如果订阅者忘记在组件销毁时取消订阅,可能会导致内存泄漏,因为订阅者仍然保留对事件总线的引用。
  • 调试和追踪:使用自定义的发布订阅模式可能会增加调试和追踪事件流的复杂性。相比内置的组件通信方式(如 props 和事件),在开发过程中可能需要更多的手动步骤来确保事件的正确发送和接收。

结语:推荐方案

在 BlueOS 开发中,组件间通信是一个重要的设计考量;选择合适的通信方式取决于应用的具体需求和场景。推荐:在父子组件间采用 props 进行数据传递和通信,因为这种方式简单直接;而对于跨级或者需要全局状态共享的通信需求,使用状态管理(如 Zustand )是更为合适的选择,可以有效降低组件间的耦合度和复杂性。如果是中小型应用,涉及到跨级组件通信,又不想引入第三方库,或可考虑通过自定义发布订阅模块完成。

BlueOS 应用开发,同样采用组件树来构建,这能带来诸多好处:代码重用、逻辑分隔、 易于维护、高内聚低耦合、快速迭代、易于测试、高可扩展性等等,各类组件(父子、兄弟、爷孙、跨级等)交织在一起,就需要解决组件通信;本文旨在探讨,BlueOS 应用开发组件之间如何通信?

组件通信方式

props 属性 / emits 事件

  • props 属性:类似于 Svelte、 React 中的 props,父组件可以通过 props 向子组件传递数据或方法。子组件可以通过 props 接收并使用这些数据或方法。
  • emits 事件:子组件可以通过触发事件来通知父组件或其他组件发生了某些操作或状态改变。通常是通过 $emit 方法触发自定义事件,并在父组件中通过监听这些事件来处理相应的逻辑。

这是 BlueOS 父子组件通信最常用、最基础的方案;但在兄弟、爷孙或其他关系组件之间使用这种方式,相对就麻烦许多,需要层层传递,不推荐采用。

在使用 props 传递数据时,需要注意以下几个事项:

  1. 命名方式:在子组件内部定义 props 时,应使用 camelCase(驼峰命名法)来命名。但在父组件中通过标签属性的方式传递数据时,应该使用 kebab-case(短横线分隔命名)的方式,即 propObject 在模板中应写作 prop-object

  2. 默认值:子组件在声明 props 时可以设置默认值。如果未传入值,则会使用这个默认值。但要注意的是,设置默认值时 props 必须以对象的形式定义,不能用数组的形式。

  3. 数据单向性:父子组件之间的 props 传递是单向的。即父组件的 props 更新,子组件会同步这些更新,但是不应该在子组件内部修改 props 的值,尤其当 props 的类型是数组或对象时,子组件内部的更改会影响父组件的状态,这可以导致不可预见的问题。

  4. 值的变更处理:若需要在子组件内部处理父组件传递的 prop 值,可以通过定义子组件自身的 data 属性或使用 $watch 来监听 props 的变化后处理。

全局状态管理

类似于 Svelte 自带的 Store 、 Vue 的 Pinia ,全局状态管理机制(如 ZustandRxJSVuex 或其他状态管理库),可以让不同组件之间共享状态。当一个组件修改了状态,其他组件可以通过订阅状态的方式获取到更新后的数据。

全局状态管理(Global State Management)在 BlueOS 应用开发中具有以下几个显著的优势:

  1. 集中管理状态:全局状态管理允许将应用中的共享状态集中存储和管理。这意味着你可以在一个单独的地方定义和更新应用的状态,而不需要在多个组件之间手动传递数据。这种集中管理可以显著简化组件间的数据流管理,使得代码更易于维护和调试。
  2. 跨组件通信:全局状态管理使得不同组件之间能够共享和同步状态,而无需通过繁琐的 props 传递或事件传递数据。当一个组件更新了状态,所有依赖于该状态的组件都可以及时获取到更新的数据,实现了组件间的解耦合和高效通信。
  3. 状态持久化:在某些场景下,全局状态管理可以方便地与本地存储结合,实现状态的持久化。例如,在用户刷新页面或重新打开应用时,可以从本地存储中恢复应用的状态,提供更好的用户体验。
  4. 方便的调试和测试: 由于状态集中管理,更容易在开发过程中对状态进行监视、调试和测试。开发者可以更方便地跟踪状态的变化,并且在开发工具中查看和修改状态,加快开发效率。
  5. 组件逻辑解耦:使用全局状态管理可以帮助降低组件之间的耦合度。组件只需关注自身的业务逻辑和展示,而不需要过多考虑数据的传递和共享,使得组件更加独立和可复用。

总之,全局状态管理是一种有效的解决方案,特别适用于中大型或复杂的项目,能够提升开发效率、代码的可维护性和应用的性能。BlueOS 官方目前尚未定制专属状态管理工具库,推荐采用开源工具库── Zustand 进行状态管理,它具有:体积小、性能好,简单易用等优势。

自定义发布-订阅

在 BlueOS 中实现跨级组件通信可以通过自定义发布订阅(Publish-Subscribe)机制来完成。以下是一个简单的示例,演示了如何使用发布订阅模式在不同级别的组件之间进行通信。

创建发布订阅模块

首先,创建一个简单的发布订阅模块,其中包括订阅、发布和取消订阅方法;用于全局事件的管理和触发。

pubsub.js
export default class EventBus {
constructor() {
this.events = {}
}
// 订阅事件
subscribe(eventName, callback) {
if (!this.events[eventName]) {
this.events[eventName] = []
}
this.events[eventName].push(callback)
}
// 发布事件
publish(eventName, ...args) {
if (this.events[eventName]) {
this.events[eventName].forEach((callback) => {
callback(...args)
})
}
}
// 取消订阅事件(可选)
unsubscribe(eventName, callback) {
if (this.events[eventName]) {
this.events[eventName] = this.events[eventName].filter(
(cb) => cb !== callback
)
}
}
}
// 创建一个全局的事件总线实例
export const eventBus = new EventBus()

跨级组件通信

主页面(父组件):引入 foobar 两个组件,并进行展示:

<template>
<div class="wrapper">
<text>{{ title }}</text>
<foo></foo>
<bar></bar>
</div>
</template>
<import name="foo" src="./../../components/Foo.ux"></import>
<import name="bar" src="./../../components/Bar.ux"></import>
<script>
export default {
data: {
title: '👏欢迎体验应用开发',
},
}
</script>
<style>
.wrapper {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: #ffe4c4;
}
</style>

子组件(Foo):监听来自 Bar 组件消息(msg-to-foo),点击按钮则触发消息(msg-to-bar):

<template>
<input
type="button"
value="Foo Component"
style="border: 1px solid #000000; padding: 5px; margin-top: 20px"
@click="onBtnClick" />
</template>
<script>
import { eventBus } from './../pubsub.js'
export default {
data: {
title: '🙌🏼 Hi, I am Foo',
},
onInit() {
eventBus.subscribe('msg-to-foo', this.handleMsgEvent)
},
onBtnClick() {
eventBus.publish('msg-to-bar', this.title)
},
handleMsgEvent(data) {
console.log('[@Foo] Received event from Bar Component:', data)
},
}
</script>

子组件(Bar):监听来自 Foo 组件消息(msg-to-bar),点击按钮则触发消息(msg-to-foo):

<template>
<input
type="button"
value="Bar Component"
style="border: 1px solid #000000; padding: 5px; margin-top: 20px"
@click="onBtnClick" />
</template>
<script>
import { eventBus } from './../pubsub.js'
export default {
data: {
title: '🤝 Hello, I am Bar',
},
onInit() {
eventBus.subscribe('msg-to-bar', this.handleMsgEvent)
},
onBtnClick() {
eventBus.publish('msg-to-foo', this.title)
},
handleMsgEvent(data) {
console.log('[@Bar] Received event from Foo Component:', data)
},
}
</script>

通过这种方式,父子组件之间不需要通过 props 或者事件传递来进行通信,而是通过事件总线实现了跨级别的组件通信,使得组件之间的耦合度更低,代码更加清晰和易于维护。但也存在一些潜在的缺点和考虑因素:

  • 全局事件管理:使用自定义的发布订阅模式可能会导致全局事件管理的复杂性增加。如果事件频繁使用,而没有清晰的命名和管理,可能会导致事件命名冲突或者难以追踪事件的来源和订阅情况。
  • 内存管理:应用开发者中,内存管理非常重要。如果订阅者忘记在组件销毁时取消订阅,可能会导致内存泄漏,因为订阅者仍然保留对事件总线的引用。
  • 调试和追踪:使用自定义的发布订阅模式可能会增加调试和追踪事件流的复杂性。相比内置的组件通信方式(如 props 和事件),在开发过程中可能需要更多的手动步骤来确保事件的正确发送和接收。

结语:推荐方案

在 BlueOS 开发中,组件间通信是一个重要的设计考量;选择合适的通信方式取决于应用的具体需求和场景。推荐:在父子组件间采用 props 进行数据传递和通信,因为这种方式简单直接;而对于跨级或者需要全局状态共享的通信需求,使用状态管理(如 Zustand )是更为合适的选择,可以有效降低组件间的耦合度和复杂性。如果是中小型应用,涉及到跨级组件通信,又不想引入第三方库,或可考虑通过自定义发布订阅模块完成。


BlueOS (中文名“蓝河操作系统”)是 vivo 自主研发的一款面向通用人工智能时代的智慧操作系统。它以智慧特性、性能优化、安全性、系统架构、AI 服务引擎、兼容性、流畅体验、开放智联等为核心特点,代表了 vivo 在操作系统领域的创新能力和研发实力。BlueOS 的目标是为用户提供一个更加智能、流畅且安全的使用体验。 BlueOS 支持 快应用 标准,推荐使用 BlueOS Studio 进行应用开发。

BlueOS Studio 是针对蓝河操作系统(BlueOS)应用开发的官方集成开发环境(IDE),它基于强大的代码编辑器 Visual Studio Code 构建,因此具备 VS Code 的全部功能,包括代码编辑、插件集成、主题定制及个性化设置等。除了继承 VS Code 的特性外,BlueOS Studio 专为 BlueOS 应用开发引入了一系列增强功能,比如智能编码补全、实时编译预览、全方位应用调试以及 UI 自动化测试等。

为了支持蓝河应用的开发,BlueOS Studio 还提供了项目管理的便捷性,如推荐的项目结构指引、依赖管理工具以及代码构建系统 BlueOS Toolkit,该工具可将源代码打包为 .rpk 格式的应用程序文件。此外,BlueOS Studio 也整合了 DevTools 模拟调试工具,类似于 Chrome DevTools,提供了丰富的调试面板以助于代码调试和性能优化。

在蓝河应用开发上, BlueOS Studio 适用于开发包括手机、手表、Pad 在内的多种应用形态,并为开发者提供丰富的开发、调试、测试和打包工具,以及项目开发的指导和文档支持,以确保开发者可以高效且方便地进行蓝河应用的开发工作。发布完成后的应用则可以供蓝河操作系统的用户使用。

您可能感兴趣的文章