使用 Lightning Message Service 跨 DOM 进行通信

使用 Lightning 消息服务在 Lightning 页面内的 DOM 之间进行通信。在同一 Lightning 页面中嵌入的 Visualforce 页面、Aura 组件和 Lightning Web 组件(包括实用程序栏中的组件和弹出式实用程序)之间进行通信。选择组件是订阅来自整个应用程序的消息,还是仅订阅来自活动区域的消息。

如果您要从 Salesforce Classic 切换到 Lightning Experience,则可以构建与现有 Visualforce 页面或 Aura 组件进行通信的 Lightning Web 组件。您还可以使用 Lightning 消息服务通过 Open CTI 与软件电话进行通信。

重要

Lightning 消息服务在 Lightning Experience 和 Experience Builder 站点中使用的 Lightning 组件中可用。

创建消息通道

要创建 Lightning 消息通道,请使用 LightningMessageChannel 元数据类型。

在组织中定义消息通道元数据

要将 LightningMessageChannel 部署到您的组织中,请创建一个 SFDX 项目。在目录中包括 XML 定义。LightningMessageChannel 文件名遵循以下格式。force-app/main/default/messageChannels/messageChannelName.messageChannel-meta.xml

有关元数据文件的示例,请参阅元数据 API 开发人员指南:LightningMessageChannel。

要将其添加到临时组织,请运行 。sf project deploy start

要将其添加到其他类型的组织(如沙盒或 Developer Edition 组织),请运行 。sf project deploy start

导入消息通道

以下是导入 Lightning 消息通道的方法,组件可以使用该通道通过 Lightning 消息服务进行通信。

// Syntax
import channelName from "@salesforce/messageChannel/channelReference";
// Syntax for resources in a managed package
import channelName from "@salesforce/messageChannel/namespace__channelReference";
// Example
import recordSelected from "@salesforce/messageChannel/Record_Selected__c";
  • channelName– 用于标识消息通道的导入符号。
  • channelReference– 消息通道的 API 名称。
  • namespace– 如果消息通道位于受管软件包中,则此值为受管软件包的名称空间。如果消息通道不在托管包中,请不要包含命名空间。

注意

Record_Selected__c指 LightningMessageChannel 元数据类型的自定义实例。尽管它使用后缀,但它不是自定义对象。__c

定义邮件服务的作用域

Lightning 消息服务允许您定义订阅组件在应用程序中接收消息的范围。您可以将范围限制为应用程序的活动区域,也可以将范围设置为整个应用程序。

重要

对于 Lightning Web 组件,范围功能仅在使用 时可用。@wire(MessageContext)

应用程序的活动区域包括选定的导航选项卡和项目、实用程序项目和 ES6 库。实用程序项目始终处于活动状态。导航选项卡和项目包括:

  • 标准导航选项卡
  • 控制台导航工作区选项卡
  • 控制台导航子选项卡
  • 控制台导航项

要从应用程序中的任何位置接收消息通道上的消息,请从 导入。然后,调用并传递可选的第四个参数。APPLICATION_SCOPElightning/messageServicesubscribe(){ scope: APPLICATION_SCOPE }subscriberOptions

// Import message service features.
import {
    subscribe,
    unsubscribe,
    APPLICATION_SCOPE,
    MessageContext
} from 'lightning/messageService';

// To pass scope, you must get a message context.
@wire(MessageContext)
    messageContext;

// Pass scope to the subscribe() method.
    subscribeToMessageChannel() {
        if (!this.subscription) {
            this.subscription = subscribe(
                this.messageContext,
                recordSelected,
                (message) => this.handleMessage(message),
                { scope: APPLICATION_SCOPE }
            );
        }
    }

从活动区域接收消息是默认行为。无需包含 scope 属性即可将范围限制为活动区域。

在消息通道上发布

要从 Lightning Web 组件在消息通道上发布消息,请在组件的 JavaScript 文件中包含作用域模块,并调用 Lightning 消息服务的函数。@salesforce/messageChannelpublish()

Lightning 消息服务将消息发布到任何订阅的组件,直到组件生命周期的销毁阶段。有时,当您离开 Lightning 页面时,组件会被缓存而不是销毁。如果 Lightning 消息服务的范围限定为整个应用程序,则这些组件仍会向 Lightning 消息服务发布消息并从 Lightning 消息服务接收消息。

提示

lwc-recipes 存储库有一个组件,用于在 Lightning 页面上发布消息以通知订阅者。Lightning 消息服务在页面上的 Visualforce、Aura 和 Lightning Web 组件之间传达该消息。lmsPublisherWebComponent

让我们看一下 lmsPublisherWebComponent 组件。组件的 HTML 模板文件显示联系人列表。选择联系人后,将调用处理程序,该处理程序将消息发布到消息通道。handleContactSelect

<!-- lmsPublisherWebComponent.html -->
<template>
  <lightning-card title="LMSPublisherWebComponent" icon-name="custom:custom30">
    <div class="slds-m-around_medium" oncontactselect={handleContactSelect}>
      <template lwc:if={contacts.data}>
        <template for:each={contacts.data} for:item="contact">
          <c-contact-list-item-bubbling
            key={contact.Id}
            contact={contact}>
          </c-contact-list-item-bubbling>
        </template>
      </template>
    </div>
  </lightning-card>
</template>

在组件的 JavaScript 文件中,导入使用消息通道所需的消息通道和 Lightning 消息服务函数。

// lmsPublisherWebComponent.js
import { LightningElement, wire } from "lwc";
import getContactList from "@salesforce/apex/ContactController.getContactList";

// Import message service features required for publishing and the message channel
import { publish, MessageContext } from "lightning/messageService";
import recordSelected from "@salesforce/messageChannel/Record_Selected__c";

export default class LmsPublisherWebComponent extends LightningElement {
  @wire(getContactList)
  contacts;

  @wire(MessageContext)
  messageContext;

  // Respond to UI event by publishing message
  handleContactSelect(event) {
    const payload = { recordId: event.target.contact.Id };

    publish(this.messageContext, recordSelected, payload);
  }
}

用于创建一个对象,该对象提供有关使用 Lightning 消息服务的 Lightning Web 组件的信息。使用适配器时,您不必与组件的任何生命周期事件进行交互。当组件被销毁时,Lightning 消息服务功能会自动注销。@wire(MessageContext)MessageContext@wire(MessageContext)

该方法创建要发布的消息内容。闪电消息服务的函数采用三个参数:消息上下文、消息通道名称和消息有效负载。在这里,消息有效负载是一个 JSON 对象,其中键的值为 。handleContactSelect()publish()recordIdevent.target.contact.Id

注意

组件必须附加到 DOM,然后才能使用用 修饰的属性。不能在函数中使用。@wire(MessageContext)@wire(MessageContext)constructor()

订阅和取消订阅消息通道

要订阅和取消订阅消息通道上的消息,请将消息通道从作用域模块导入到 Lightning Web 组件中。调用 Lightning 消息服务和函数。@salesforce/messageChannelsubscribe()unsubscribe()

提示

lwc-recipes 存储库有一个组件,用于显示如何订阅和取消订阅消息通道。此示例适用于“在消息通道上发布”中的发布者组件。lmsSubscriberWebComponent

让我们看一下 lmsSubscriberWebComponent 组件。从发布者组件中选择联系人会将所选记录 ID 发布到消息通道。Record_Selected__c

订阅者组件的 HTML 对已发布的消息做出反应,并显示其记录 ID 通过消息负载提供的联系人的数据。

<!-- lmsSubscriberWebComponent.html -->
<template>
  <lightning-card title="LMSSubscriberWebComponent" icon-name="custom:custom30">
    <div class="slds-m-around_medium">
      <template lwc:if={Picture__c}>
        <img src={Picture__c} alt="Profile photo" />
      </template>
      <p>{Name}</p>
      <p>{Title}</p>
      <p>
        <lightning-formatted-phone value={Phone}></lightning-formatted-phone>
      </p>
      <p>
        <lightning-formatted-email value={Email}></lightning-formatted-email>
      </p>
    </div>
  </lightning-card>
</template>

在组件的 JavaScript 中,导入从 订阅所需的消息服务功能。从 导入消息通道。lightning/messageServiceRecord_Selected__c@salesforce/messageChannel

用于创建 Context 对象,该对象提供有关使用 Lightning 消息服务的 Lightning Web 组件的信息。组件必须附加到 DOM,然后才能使用用 修饰的属性。@wire(MessageContext)@wire(MessageContext)

该函数检查是否为 null。如果订阅为 null,则调用 Lightning 消息服务的方法并将其分配给 。该方法采用三个必需的参数:消息上下文、消息通道的名称以及处理已发布消息的侦听器方法。调用侦听器方法时,它会将消息传递给 。 从它收到的 JSON 消息有效负载中提取属性。然后,使用与记录 ID 匹配的联系人相关的信息更新 HTML 模板。subscribeToMessageChannel()subscriptionsubscribe()subscriptionsubscribe()handleMessage()handleMessage()recordId

若要从应用程序中的任何位置接收消息通道上的消息,请将该方法的第四个参数作为可选参数传递。请参阅定义邮件服务的作用域。{ scope: APPLICATION_SCOPE }subscribe()

要停止接收来自 Lightning 消息服务的消息,请调用 ,传入订阅引用。该对象包含对要取消订阅的订阅的引用。此示例调用 ,后者调用 ,然后设置为 null。unsubscribe()subscriptionunsubscribeToMessageChannel()unsubscribe()subscription

// lmsSubscriberWebComponent.js
import { LightningElement, wire } from "lwc";
import { getRecord, getFieldValue } from "lightning/uiRecordApi";
import { ShowToastEvent } from "lightning/platformShowToastEvent";
import { reduceErrors } from "c/ldsUtils";

// Import message service features required for subscribing and the message channel
import {
  subscribe,
  unsubscribe,
  APPLICATION_SCOPE,
  MessageContext,
} from "lightning/messageService";
import recordSelected from "@salesforce/messageChannel/Record_Selected__c";

import NAME_FIELD from "@salesforce/schema/Contact.Name";
import TITLE_FIELD from "@salesforce/schema/Contact.Title";
import PHONE_FIELD from "@salesforce/schema/Contact.Phone";
import EMAIL_FIELD from "@salesforce/schema/Contact.Email";
import PICTURE_FIELD from "@salesforce/schema/Contact.Picture__c";

const fields = [NAME_FIELD, TITLE_FIELD, PHONE_FIELD, EMAIL_FIELD, PICTURE_FIELD];

export default class LmsSubscriberWebComponent extends LightningElement {
  subscription = null;
  recordId;

  Name;
  Title;
  Phone;
  Email;
  Picture__c;

  @wire(getRecord, { recordId: "$recordId", fields })
  wiredRecord({ error, data }) {
    if (error) {
      this.dispatchToast(error);
    } else if (data) {
      fields.forEach((item) => (this[item.fieldApiName] = getFieldValue(data, item)));
    }
  }

  @wire(MessageContext)
  messageContext;

  // Encapsulate logic for Lightning message service subscribe and unsubsubscribe
  subscribeToMessageChannel() {
    if (!this.subscription) {
      this.subscription = subscribe(
        this.messageContext,
        recordSelected,
        (message) => this.handleMessage(message),
        { scope: APPLICATION_SCOPE },
      );
    }
  }

  unsubscribeToMessageChannel() {
    unsubscribe(this.subscription);
    this.subscription = null;
  }

  // Handler for message received by component
  handleMessage(message) {
    this.recordId = message.recordId;
  }

  // Standard lifecycle hooks used to subscribe and unsubsubscribe to the message channel
  connectedCallback() {
    this.subscribeToMessageChannel();
  }

  disconnectedCallback() {
    this.unsubscribeToMessageChannel();
  }

  // Helper
  dispatchToast(error) {
    this.dispatchEvent(
      new ShowToastEvent({
        title: "Error loading contact",
        message: reduceErrors(error).join(", "),
        variant: "error",
      }),
    );
  }
}

注意

如果创建的服务组件不是 ,则不能用于创建对象。而是从 import 和 methods。用于创建 Context 对象并将其分配给字段,如 .然后,传入方法。不会自动为服务组件发布上下文。调用以删除与组件的消息上下文关联的任何订阅。LightningElement@wire(MessageContext)MessageContextcreateMessageContext()releaseMessageContext()lightning/messageServicecreateMessageContext()messageContextmessageContextsubscribe()releaseMessageContext(messageContext)

Lightning 消息服务限制

使用 Lightning 消息服务时,请记住以下几点。

Lightning 消息服务仅支持以下体验:

  • Lightning Experience 标准导航
  • Lightning Experience 控制台导航
  • 适用于 Aura 和 Lightning Web 组件的 Salesforce 移动应用程序,但不适用于 Visualforce 页面
  • Aura 和基于 LWR 的 Experience Builder 站点中使用的 Lightning 组件。注意Lightning 消息服务不适用于 Salesforce 选项卡 + Visualforce 站点或 Experience Builder 站点中的 Visualforce 页面。

在不支持 Lightning 消息传递服务的容器中,使用该模块。从 github.com/developerforce/pubsub 下载模块。pubsub

在 AppExchange 上发布的包中包含消息通道时,支持 1GP 和 2GP 包。

对于 Lightning Web 组件,您可以定义订阅组件仅在使用 时在应用程序中接收消息的范围。@wire(MessageContext)

使用移动设备功能

移动功能允许您在 Lightning Web 组件中使用移动设备功能。直接从您的组件代码访问摄像头和位置检测硬件,以及联系人和日历数据等平台功能。使用这些特定于移动设备的功能构建感觉像本机移动应用程序的 Lightning 应用程序。

《移动和离线开发人员指南》中提供了完整的详细信息,该指南是执行移动开发时本指南的重要配套。