本篇參考:

https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.use_quick_actions

https://developer.salesforce.com/docs/component-library/bundle/lightning-quick-action-panel/documentation

背景: 我們現在專案越來越多的使用 lwc 進行了前端開發,當然我們知道lwc並不能所有的場景都支援自己玩,比如元件之間的navigation、 quick action等都需要通過aura進行操作,aura套用lwc來實現。好訊息是隨著salesforce的release對lwc的不斷髮力,越來越多的功能可以通過lwc來使用。

一. lwc 適配 Quick Action的兩個型別

首先我們先想一下我們通過Aura使用到Quick Action的場景,總結起來可以簡單的歸到2點:

1. 彈出一個popup modal,modal中展示一個UI,不管是一個可以用於修改的表單,還是展示只讀內容然後有操作按鈕等等,這些都無所謂了,重點是有UI的內容,展示modal;

2. 點選以後執行一個web service或者做一個跳轉操作,使用者不希望彈出來modal,只是希望進行即可。

當然,不同的甲方不同的需求會有不同的實現方案,但是Quick Action當我們選擇 Aura的時候,通常這兩個大的型別就可以搞定的。切回到 lwc,同樣官方也提供了這兩個類似的模式。

  • ScreenAction: 用於宣告一個有popup modal的UI的quick action;
  • Action: 無UI的quick action。

這兩種配置是配置到js-meta.xml裡面。配置資訊如下:

ScreenAction: 以下的配置是 ScreenAction的配置,主要有幾個點:

  • apiVersion建議選擇52.0,如果有後續的release,當然也可以選擇這個值即以上,目前來講,選擇52.0,嘗試了一下,如果選擇50、51也可以儲存,但是為了考慮未知的風險,儘量還是按照規矩來;
  • target設定成 lightning__RecordAction:這個是52 release新有的配置項,需要了解的一點是,如果使用 lwc的quick action,只支援 record 的quick action,global action是不支援的;
  • targetConfig中配置的 actionType為 ScreenAction,當然,如果不配置 targetConfig,預設也是 ScreenAction,所以我們在配置時,預設可以不配置targetConfigs部分;
<?xml version="1.0" encoding="UTF-8" ?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>52.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__RecordAction</target>
</targets>
<targetConfigs>
<targetConfig targets="lightning__RecordAction">
<actionType>ScreenAction</actionType>
</targetConfig>
</targetConfigs>
</LightningComponentBundle>

Action:和上述的區別只是 actionType為 Action,如果想要選擇 Action型別,則下述所有的內容都無法省略。

<?xml version="1.0" encoding="UTF-8" ?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>52.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__RecordAction</target>
</targets>
<targetConfigs>
<targetConfig targets="lightning__RecordAction">
<actionType>Action</actionType>
</targetConfig>
</targetConfigs>
</LightningComponentBundle>

 二. ScreenAction的使用

配置篇已經搞定,接下來就搞一下UI,根據官方的demo,我們做一下contact的編輯的一個component quick action。

screenActionSample.js: 主要用於contact的獲取資料以及編輯。這裡面有兩個關鍵點。

  • CloseActionScreenEvent是salesforce lwc提供的關閉action的事件,類似於aura的e.force:closeQuickAction。同樣,如果lwc想要關閉,只需要this.dispatchEvent(new CloseActionScreenEvent());即可,類似於aura的$A.get("e.force:closeQuickAction").fire();
  • 我們無法捕捉到X這個關閉按鈕,所以同樣也沒法在這個操作中監聽事件(如果大神們可以監聽到,麻煩告知,我這裡在修改)。
import { LightningElement, api, wire,track } from 'lwc';
import { getRecord, getFieldValue } from 'lightning/uiRecordApi';
import { updateRecord } from 'lightning/uiRecordApi';
import { CloseActionScreenEvent } from 'lightning/actions';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import FNAME_FIELD from '@salesforce/schema/Contact.FirstName';
import LNAME_FIELD from '@salesforce/schema/Contact.LastName';
import PHONE_FIELD from '@salesforce/schema/Contact.Phone';
import ID_FIELD from '@salesforce/schema/Contact.Id'; const FIELDS = [FNAME_FIELD, LNAME_FIELD, PHONE_FIELD];
export default class screenActionSample extends LightningElement {
disabled = false;
@api recordId;
@api objectApiName; contact; @track firstName; @track lastName; @track phone; @wire(getRecord, { recordId: '$recordId', fields: FIELDS })
wiredRecord({ error, data }) {
if (error) {
//TODO
} else if (data) {
this.contact = data;
this.firstName = this.contact.fields.FirstName.value;
this.lastName = this.contact.fields.LastName.value;
this.phone = this.contact.fields.Phone.value;
}
} handleCancel(event) {
// Add your cancel button implementation here
this.dispatchEvent(new CloseActionScreenEvent());
} handleChange(event) {
let source = event.target.name;
if(source === 'firstName') {
this.firstName = event.target.value;
} else if(source === 'lastName') {
this.lastName = event.target.value;
} else if(source === 'phone') {
this.phone = event.target.value;
}
} handleSubmit(e) {
// Add your updateRecord implementation
const fields = {};
fields[ID_FIELD.fieldApiName] = this.recordId;
fields[FNAME_FIELD.fieldApiName] = this.firstName;
fields[LNAME_FIELD.fieldApiName] = this.lastName;
fields[PHONE_FIELD.fieldApiName] = this.phone;
const recordInput = { fields };
console.log(JSON.stringify(recordInput));
updateRecord(recordInput)
.then(() => {
this.dispatchEvent(
new ShowToastEvent({
title: 'Success',
message: 'Contact updated',
variant: 'success'
})
);
this.dispatchEvent(new CloseActionScreenEvent());
})
.catch(error => {
this.dispatchEvent(
new ShowToastEvent({
title: 'Error creating record',
message: error.body.message,
variant: 'error'
})
);
});
}
}

screenAction.html:這裡我們看到一個新的元件的面孔: lightning-quick-action-panel。我們查閱官方文件以後,發現這個使用起來很簡單,就是基於lightning design system中的modal來實現,屬性中可以設定 header屬性,代表action的頭部,slot設定了footer的placeholder。

<template>
<lightning-quick-action-panel header="Quick Contact Edit"> <lightning-input label="First Name" name="firstName" value={firstName} class="slds-m-bottom_x-small" onchange={handleChange}></lightning-input>
<lightning-input label="Last Name" name="lastName" value={lastName} onchange={handleChange} class="slds-m-bottom_x-small" required></lightning-input>
<lightning-input label="Phone" type="tel" name="phone" value={phone} onchange={handleChange} class="slds-m-bottom_x-small"></lightning-input> <div slot="footer">
<lightning-button variant="neutral" label="Cancel" onclick={handleCancel}></lightning-button>
<lightning-button variant="brand" class="slds-m-left_x-small" label="Save" type="submit" onclick={handleSubmit} disabled={disabled}></lightning-button>
</div>
</lightning-quick-action-panel>
</template>

整體展示的效果:

我們來看一下解析的html,這個模型和官方的modal模型是不是很像。

當然,官方除了可以使用 lightning-quick-action-panel元件以外,也支援自己使用html去適配。

三. headless的action效果

headless的action是通過呼叫 invoke方法來執行,invoke方法前面通過 @api 註解來宣告。如果需要非同步操作或者需要訪問後臺等在進行操作,可以將方法宣告稱非同步,即:@api async invoke() {}

舉一個官方的demo:用來點選quick action跳轉到 contact list

import { LightningElement, track, wire,api } from 'lwc';
import { NavigationMixin } from 'lightning/navigation';
export default class headlessActionSAmple extends NavigationMixin(LightningElement) {
@api invoke() {
this[NavigationMixin.Navigate]({
type: 'standard__objectPage',
attributes: {
objectApiName: 'Contact',
actionName: 'home',
},
});
}
}

四. 問題思考

優點: 對於優點來說,太顯而易見了。 基於modal的設計,支援了lwc,還有什麼比這個更好的優點嗎

缺點:

1. 和aura彈出modal不同,aura的URL不會改變,lwc會改變URL,兩邊不統一,針對彈出modal以後的重新整理操作,lwc載入資料等可能會有潛在的問題,需要測試和適配。舉個例子,上述的ScreenAction的demo,初始化彈出來是正常的,但是當你點選重新整理按鈕或者點選F5以後,頁面將會進入假死狀態,這種情況可能要考慮一下優化程式碼。

2. lwc彈出的modal的寬度是固定的,如果客戶希望更改lwc彈出的modal的寬度,則無法實現,這種在aura可以通過 aura:tag注入可以搞定
3. 如果基於screen action的modal,目前 lightning-quick-action-panel 還是beta版,專案要求高的,客戶不一定接受。
4. 目前 lwc quick action不支援 salesforce mobile app,有mobile相關的專案,使用前一定要考慮限制,別做完以後電腦端沒有問題,手機端是用不了。

總結:篇中主要介紹lwc如何去適配quick action。篇中有錯誤地方歡迎指出,有不懂歡迎留言。