Salesforce LWC 组件间通信
LWC组件间通信,通常是父子组件通信和非父子组件通信,一般有三种场景:
- 父组件向子组件传递值。一般在子组件的变量或方法使用
@api
注解,由父组件向@api
公开的变量传递值,或调用子组件方法。 - 子组件向父组件传递值。一般使用CustomEvent,子组件通过dispatchEvent发出一个事件,由父组件监听。
- 非父子组件传递值。一般使用LMS(Lightning Message Service),这是一种发布订阅模式,由发布者发布event,再由订阅者订阅,接收payload。
一、父子组件传值
1.1 父组件向子组件传递值
第一,子组件中使用@api
公开变量(方法)即可。
sonLwc.js
scala
import { LightningElement, api } from 'lwc';
import LightningAlert from 'lightning/alert';
export default class SonLwc extends LightningElement {
@api itemName = 'Test';
@api alertItemNameInfo() {
LightningAlert.open({
message: this.itemName,
theme: 'info'
});
}
}
第二,父组件调用子组件,通过c-
的方式引用子组件,公开的变量也使用同样的方式去传递值。
parentLwc.html
xml
<template>
<lightning-card title="Parent LWC" icon-name="custom:custom63">
<div>
<div>
<span>send parent data to son lwc</span>
<!-- 引用子组件,名字首字母前加上了 c加上破折号(-),api公开的变量同样。c是默认的命名空间 -->
<c-son-lwc item-name={sonItemName}></c-son-lwc>
<lightning-button label="alert item info" onclick={handleAlertItemNameEvent}></lightning-button>
</div>
</div>
</lightning-card>
</template>
parentLwc.js
scala
import { LightningElement, api, track, wire } from 'lwc';
export default class ParentLwc extends LightningElement {
sonItemName = 'test parent for son item';
handleAlertItemNameEvent() {
this.template.querySelector('c-son-lwc').alertItemNameInfo();
}
}
这里使用了button去触发子组件方法,方法中弹出了当前子组件itemName的值,点击后可以观察到,子组件值已被父组件覆盖。说明父组件已经将值传递给子组件,并且也能够触发子组件方法。
1.2 子组件向父组件传递值
第一,子组件需要通过CustomEvent的方式去发出一个事件,由父组件监听。可以使用一个button来做触发动作。
sonLwc.html
xml
<template>
<lightning-button label="send data to parent lwc" onclick={handleSendData}></lightning-button>
</template>
sonLwc.js
scala
import { LightningElement, api } from 'lwc';
import LightningAlert from 'lightning/alert';
export default class SonLwc extends LightningElement {
itemValue = "Hello from Son Component";
handleSendData() {
const customEvent = new CustomEvent("senddata", {
detail: {
message: this.itemValue,
}
});
this.dispatchEvent(customEvent); // 主要功能是将一个事件对象分发到指定的 DOM 元素上,从而触发该元素上绑定的事件监听器
}
}
CustomEvent构造时,name建议全小写,detail中可以设这么用于传递的数据。还有诸如bubbles
,composed
等参数可以设定。请参考Events Best Practices
第二,父组件通过on-eventname
监听事件,并从中取到子组件传递的数据。
parentLwc.html
xml
<template>
<lightning-card title="Parent LWC" icon-name="custom:custom63">
<div>
<div>
<span>send parent data to son lwc</span>
<!-- 引用子组件,名字首字母前加上了 c加上破折号(-),api公开的变量同样。c是默认的命名空间 -->
<c-son-lwc onsenddata={handleDataReceived}></c-son-lwc>
<p>Data received from Son Component: {receivedMessage}</p>
</div>
</div>
</lightning-card>
</template>
parentLwc.js
scala
import { LightningElement, api, track, wire } from 'lwc';
export default class ParentLwc extends LightningElement {
receivedMessage;
handleDataReceived(event) {
this.receivedMessage = event.detail.message;
}
}
通过点击button,就可以看到子组件的值会传递给父组件。
二、非父子组件传值
对于非父子组件传值,Salesforce提供了Lightning Message Service的标准方法去实现。LMS可以实现LWC,Aura,Visualforce Page之间的跨组件通信。
第一步,需要先创建messageChannels
,messageChannels只能通过metadata的方式创建。
xml
<?xml version="1.0" encoding="UTF-8"?>
<LightningMessageChannel xmlns="http://soap.sforce.com/2006/04/metadata">
<description>Message Channel to pass a field value</description>
<isExposed>true</isExposed>
<masterLabel>FieldValueTransfer</masterLabel>
</LightningMessageChannel>
第二步,创建publisher组件
publisherLwc.html
xml
<template>
<lightning-card title="Publisher Component" icon-name="custom:custom63">
<div class="slds-m-around_medium">
<lightning-input label="Enter Message" value={messageText} onchange={handleInputChange}></lightning-input>
<lightning-button label="Send Message" onclick={handleSend}></lightning-button>
</div>
</lightning-card>
</template>
publishLwc.js
typescript
import { LightningElement, api, track, wire } from 'lwc';
import { publish, MessageContext } from 'lightning/messageService';
import MY_MESSAGE_CHANNEL from '@salesforce/messageChannel/FieldValueTransfer__c';
export default class PublisherComponent extends LightningElement {
messageText = '';
@wire(MessageContext)
messageContext;
handleInputChange(event) {
this.messageText = event.target.value;
}
handleSend() {
const message = { data: this.messageText};
publish(this.messageContext, MY_MESSAGE_CHANNEL, message);
}
}
第三步,创建subscriber组件
subscriberLwc.html
xml
<template>
<lightning-card title="Subscriber Component" icon-name="custom:custom63">
<div class="slds-m-around_medium">
<p>Received Message: {receivedMessage}</p>
</div>
</lightning-card>
</template>
subscriberLwc.js
typescript
import { LightningElement, wire } from 'lwc';
import { subscribe, MessageContext } from 'lightning/messageService';
import MY_MESSAGE_CHANNEL from '@salesforce/messageChannel/FieldValueTransfer__c';
export default class SubscriberComponent extends LightningElement {
subscription = null;
receivedMessage = '';
@wire(MessageContext)
messageContext;
connectedCallback() {
this.subscribeToMessageChannel();
}
subscribeToMessageChannel() {
if (this.subscription) {
return;
}
this.subscription = subscribe(this.messageContext, MY_MESSAGE_CHANNEL, (message) => {
this.handleMessage(message);
});
}
handleMessage(message) {
this.receivedMessage = message.data;
}
}
将publisher和subscriber放到同一个lightning page,就可以观察到效果。由publisher发送一条数据,subscriber就可以接收到这条数据。
关于LMS的更多内容,请见lightning-message-service