概要
Visualforce ページに埋め込まれた Lightning Web コンポーネント (LWC) との通信には、以下の方法があります。
- JavaScript イベントを使用
- Lightning Message Service (LMS) を使用
これらの実装方法をサンプルコード付きで説明します。
前提条件
- 本記事では説明に必要なソースコードのみ記載します。サンプルコードの全メタデータは GitHub リポジトリ『ykars/sf-visualforce-and-lwc-integration』をご参照ください。
- Visualforce ページに LWC を埋め込む方法として Lightning Out を使用しています。Lightning Out の使用方法については『Visualforce ページ | Salesforce 対象でのコンポーネントの使用 | Salesforce 対象でのコンポーネントの使用 | Lightning Web Components 開発者ガイド | Salesforce Developers』をご参照ください。
- Visualforce タブに配置された Visualforce ページを想定しています。Lightning ページに配置された Visualforce の挙動は検証できていないことをご了承ください。
JavaScript イベントを使用する方法
サンプルコードの画面構成
Visualforce ページ
LWC の親となる Visualforce ページです。
- LWC からのイベントを受信するために、
addEventListener
関数を使用してイベントリスナーを追加します。 - LWC にデータを渡す際は LWC の
addVfMessage
関数を呼び出して渡します。
JsEventParent.page
<apex:page>
<!-- Lightning 関連のライブラリをインポート -->
<apex:includeLightning />
<apex:form>
<apex:pageBlock title="Visualforce">
<!-- LWC にメッセージを送信するボタン -->
<apex:pageBlockButtons>
<apex:commandButton
value="LWC にメッセージを送信"
onclick="handleSendMessageToLwc();"
oncomplete="return null;"
></apex:commandButton>
</apex:pageBlockButtons>
<apex:pageBlockSection columns="2">
<!-- LWC からのメッセージ表示領域 -->
<apex:pageBlockSectionItem>
<h2>LWC からのメッセージ</h2>
<div class="lwc-message-list"></div>
</apex:pageBlockSectionItem>
<!-- LWC 埋め込み領域 -->
<apex:pageBlockSectionItem>
<div id="lwc-container"></div>
</apex:pageBlockSectionItem>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>
<script>
// Lightning Out を使用して LWC をページに埋め込む
$Lightning.use('c:jsEventChildContainer', function() {
$Lightning.createComponent(
'c:jsEventChild',
{
vfMessages: [{ key: 0, value: 'Hello!', timestamp: new Date().toLocaleTimeString() }]
},
'lwc-container',
function(cmp) {
console.log('Visualforce ページに LWC が追加されました:' + cmp);
// LWC にイベントリスナーを設定
const lwc = document.querySelector('c-js-event-child');
lwc.addEventListener('message', handleLwcMessage);
}
);
});
/**
* LWC からのメッセージ受信時ハンドラ
* @param {Event} event イベント
*/
function handleLwcMessage(event) {
const lwcMessage = event.detail.message;
const lwcMessageElement = document.createElement('p');
lwcMessageElement.textContent = lwcMessage;
const lwcMessageListElement = document.querySelector('.lwc-message-list');
lwcMessageListElement.appendChild(lwcMessageElement);
}
/**
* LWC にメッセージを送信する
*/
function handleSendMessageToLwc() {
// LWC の @api 関数を呼び出す
const lwc = document.querySelector('c-js-event-child');
lwc.addVfMessage('Hello from Visualforce!');
}
</script>
</apex:page>
Lightning Web コンポーネント
Visualforce ページに埋め込む LWC です。
-
addVfMessage
関数を Visualforce ページから呼び出せるようにするために@api
デコレータを付けます。 - Visualforce にデータを送信するには、CustomEvent をディスパッチします。
jsEventChild.js
import { LightningElement, api } from 'lwc';
export default class JsEventChild extends LightningElement {
/**
* Visualforce からのメッセージ
* @type {{ key: number; value: string; timestamp: string; }[]}
*/
@api
vfMessages = [];
/**
* Visualforce からのメッセージを追加する
* @param {string} message Visualforce メッセージ
*/
@api
addVfMessage(message) {
const newVfMessage = {
key: this.vfMessages.length,
value: message,
timestamp: new Date().toLocaleTimeString()
};
this.vfMessages = [...this.vfMessages, newVfMessage];
}
/**
* 「Visualforce にメッセージを送信」ボタン押下時ハンドラ
*/
handleSendMessageToVf() {
// CustomEvent を発行
const event = new CustomEvent("message", {
detail: {
message: 'Hello from LWC!'
}
});
this.dispatchEvent(event);
}
}
Lightning Message Service を使用する方法
サンプルコードの画面構成
Lightning Message Channel
Visualforce ページと LWC 間で通信するためのメッセージを定義します。
-
message
項目にメッセージ内容を含めます。 - Visualforce ページと LWC のそれぞれで公開と購読の両方が行われるため、自分自身が公開したメッセージも受信することになります。自分自身が公開したメッセージは読み飛ばす処理を実装するために、「どこから公開されたのか」を表す
publisher
項目を用意しています。
Message.messageChannel-meta.xml
<LightningMessageChannel xmlns="http://soap.sforce.com/2006/04/metadata">
<masterLabel>Message</masterLabel>
<isExposed>true</isExposed>
<description>Visualforce に埋め込まれた LWC との通信に使用するメッセージチャネル</description>
<lightningMessageFields>
<fieldName>publisher</fieldName>
<description>公開者。VF:Visualforce, LWC:Lightning Web コンポーネント</description>
</lightningMessageFields>
<lightningMessageFields>
<fieldName>message</fieldName>
<description>メッセージ</description>
</lightningMessageFields>
</LightningMessageChannel>
Visualforce ページ
LWC の親となる Visualforce ページです。
-
$Lightning.createComponent
関数の第2引数で、LWC にメッセージチャネル、sforce.one.publish
、sforce.one.subscribe
を渡します。LWC 側ではこれらを使用して LMS を公開・購読します。
LmsParent.page
<apex:page>
<!-- Lightning 関連のライブラリをインポート -->
<apex:includeLightning />
<apex:form>
<apex:pageBlock title="Visualforce">
<!-- LWC にメッセージを送信するボタン -->
<apex:pageBlockButtons>
<apex:commandButton
value="LWC にメッセージを送信"
onclick="handleSendMessageToLwc();"
oncomplete="return null;"
></apex:commandButton>
</apex:pageBlockButtons>
<apex:pageBlockSection columns="2">
<!-- LWC からのメッセージ表示領域 -->
<apex:pageBlockSectionItem>
<h2>LWC からのメッセージ</h2>
<div class="lwc-message-list"></div>
</apex:pageBlockSectionItem>
<!-- LWC 埋め込み領域 -->
<apex:pageBlockSectionItem>
<div id="lwc-container"></div>
</apex:pageBlockSectionItem>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>
<script>
// メッセージチャネルを購読する
const MESSAGE_CHANNEL = "{!$MessageChannel.Message__c}";
let subscription = sforce.one.subscribe(MESSAGE_CHANNEL, handleInboundMessage, { scope: 'APPLICATION' });
// Lightning Out を使用して LWC をページに埋め込む
$Lightning.use('c:lmsChildContainer', function() {
$Lightning.createComponent(
'c:lmsChild',
{
messageChannel: MESSAGE_CHANNEL,
publish: sforce.one.publish,
subscribe: sforce.one.subscribe
},
'lwc-container',
function(cmp) {
console.log('Visualforce ページに LWC が追加されました:' + cmp);
publishMessage('Hello!');
}
);
});
/**
* メッセージチャネル受信時ハンドラ
* @param {MessageChannel} message メッセージチャネルレコード
*/
function handleInboundMessage(message) {
if (message.publisher === 'LWC') {
const lwcMessage = message.message;
const lwcMessageElement = document.createElement('p');
lwcMessageElement.textContent = lwcMessage;
const lwcMessageListElement = document.querySelector('.lwc-message-list');
lwcMessageListElement.appendChild(lwcMessageElement);
}
}
/**
* LWC にメッセージを送信する
*/
function handleSendMessageToLwc() {
publishMessage('Hello from Visualforce!');
}
/**
* メッセージチャネルを公開する
*/
function publishMessage(message) {
const payload = {
publisher: 'VF',
message: message
};
sforce.one.publish(MESSAGE_CHANNEL, payload);
}
</script>
</apex:page>
Lightning Web コンポーネント
Visualforce ページに埋め込む LWC です。
- Visualforce から受け取った
messageChannel
、publish
、subscribe
を使用して LWS を公開・購読します。
LWC で LMS を使用する一般的は方法は lightning/messageService
モジュールをインポートして使用することですが、この方法では Visualforce ページと LWC 間で通信できなかったため、Visualforce ページからメッセージチャネル、sforce.one.publish
、sforce.one.subscribe
を受け取り使用しています。
しかし、この方法は Salesforce のドキュメントに載っていないため、サポートされていない可能性があります。
lmsChild.js
import { LightningElement, api } from 'lwc';
export default class LmsChild extends LightningElement {
/**
* メッセージチャネル
*/
@api
messageChannel;
/**
* メッセージチャネルを公開する
* @type {(messageChannel: any, payload: any) => void}
*/
@api
publish;
/**
* メッセージチャネルを購読する
* @type {(messageChannel: any, listener: (message: any) => void) => any}
*/
@api
subscribe;
/**
* Visualforce からのメッセージ
* @type {{ key: number; value: string; timestamp: string; }[]}
*/
vfMessages = [];
/**
* 初期処理
*/
connectedCallback() {
// メッセージチャネルを購読する
if (this.messageChannel && this.subscribe) {
this.subscribe(this.messageChannel, this.handleInboundMessage.bind(this));
}
}
/**
* 「Visualforce にメッセージを送信」ボタン押下時ハンドラ
*/
handleSendMessageToVf() {
// メッセージチャネルを公開する
const payload = {
publisher: 'LWC',
message: 'Hello from LWC!'
};
this.publish(this.messageChannel, payload);
}
/**
* メッセージチャネル受信時ハンドラ
* @param {MessageChannel} message メッセージチャネルレコード
*/
handleInboundMessage(message) {
// 受信したメッセージを「Visualforce からのメッセージ」に表示する
if (message.publisher === 'VF') {
const newVfMessage = {
key: this.vfMessages.length,
value: message.message,
timestamp: new Date().toLocaleTimeString()
};
this.vfMessages = [...this.vfMessages, newVfMessage];
}
}
}
参考資料
- Visualforce ページ | Salesforce 対象でのコンポーネントの使用 | Salesforce 対象でのコンポーネントの使用 | Lightning Web Components 開発者ガイド | Salesforce Developers
- Lightning Message Service を使用した DOM 間の通信 | Visualforce 開発者ガイド | Salesforce Developers
- Lightning Message Service | Salesforce 対象でのコンポーネントの使用 | Salesforce 対象でのコンポーネントの使用 | Salesforce 対象でのコンポーネントの使用 | Lightning Web Components 開発者ガイド | Salesforce Developers
- visualforce-to-lwc/force-app/main/default/pages/interoperability.page at main · trailheadapps/visualforce-to-lwc · GitHub
- Vue3で作っているVisualforceページでLWCを使う