Lightning Web Components 之间的通信

掌握 LWC 组件通信的全部三种模式。本文讲解:子到父用标准 DOM CustomEvents(detail 数据负载、bubbles:true 冒泡、composed:true 穿越 Shadow DOM 边界)、父到子用 @api 的三种模式(响应式公共属性、命令式公共方法、getter/setter 拦截变化)、以及无关联组件用 Lightning Message Service 发布-订阅(消息通道元数据、publish/subscribe、何时选 LMS vs DOM 事件),覆盖每个生产 LWC 应用的通信主干。...

📅 2026/10/5 ✍️ ponybai 🏷️ salesforce, developer, lwc, headless

一、从子组件到父组件通信

slide_2

当子组件需要告诉父组件某件事时,它用标准 DOM CustomEvents。本单元创建并派发带数据负载的事件,用关键的 bubbles:true 和 composed:true 标志让事件沿组件层级向上传播——甚至穿越 Shadow DOM 边界。

用 Custom Events 从子到父

slide_3

子组件——创建并派发 CustomEvent:

handleClick() {
  const event = new CustomEvent('itemselected', {
    detail: { id: this.itemId, name: this.itemName }
  });
  this.dispatchEvent(event);
}

父组件——监听并处理:模板 <c-child onitemselected={handleItemSelected}>,JS handleItemSelected(event) { const { id, name } = event.detail; }。

让事件冒泡穿过层级:无标志时只有直接父组件能听到事件(Shadow DOM 边界阻止传播);bubbles: true 让事件沿 DOM 树向上传播;composed: true 让事件穿越 Shadow DOM 边界(LWC 每个组件有自己的 Shadow DOM,没有 composed:true 事件会被困住);两者都设时,孙组件的事件能被任何祖先听到。

关键原则:让事件尽可能局部——只有直接父组件需要就开冒泡,只有直接父组件之上的祖先真正需要才设 composed:true。

二、从父组件到子组件通信

slide_4

父到子通信用 @api——把属性和方法暴露为公共的装饰器。覆盖三种模式:从 HTML 响应式设置公共属性、从 JavaScript 命令式调用公共方法、用 getter/setter 拦截并响应属性变化。

父到子——三种 @api 模式

slide_5

1. 更新公共属性——响应式,最常见:子组件 @api itemName;、@api quantity = 0;;父模板 <c-order-item item-name={product.name} quantity={product.qty}>——product.name 变化时子组件自动收到新值,响应式、无需代码。

2. 调用公共函数——命令式控制:子组件 @api reset() { this.quantity = 0; };父 JS this.template.querySelector('c-order-item').reset()。用于验证、重置、聚焦、刷新——父组件需要触发的动作而非传递的数据。

3. Getter 和 Setter——拦截属性变化:@api get itemName() { return this._itemName; } set itemName(value) { this._itemName = value; this.validate(); }。用于需要验证、转换、或响应属性变化的业务逻辑。

默认值来自 JavaScript,而非父组件——父组件只在显式传值时覆盖。

三、无关联组件之间的通信

slide_6

组件没有父子关系时怎么办?Lightning Message Service 提供发布-订阅模式,通过元数据定义的命名消息通道连接任意组件到任意组件——不同 App Builder 区域、不同 DOM 子树、甚至不同浏览器标签。

Lightning Message Service——完整模式

slide_7

LMS 连接没有共享父组件的组件——不同 App Builder 插槽、不同标签、不同窗口。

1. 消息通道(元数据 XML):定义在 messageChannels/ 目录,含 <LightningMessageChannel>、<isExposed>true</isExposed>、<lightningMessageFields>(字段名)。

2. 发布者:import { publish, MessageContext } from 'lightning/messageService'、@wire(MessageContext) messageContext,然后 publish(this.messageContext, Count_Updated, { operator: 'add', constant: 5 })。

3. 订阅者:import { subscribe, MessageContext }、this.subscription = subscribe(this.messageContext, Count_Updated, (message) => this.handleMessage(message))。

何时选 LMS vs DOM 事件:DOM CustomEvents → 父子关系,更高效,优先用;LMS → 无关联组件、不同子树、LWC 到 Aura 桥接、多标签同步(也兼容 Visualforce 页面)。别过度用 LMS——DOM 事件更快更简单且无需 XML 文件,LMS 是组件真正没有共同祖先时的逃生舱。


文章来源:Trailhead - Communicate Between Lightning Web Components