1. 程式人生 > >Salesforce LWC學習(十) 前端處理之 list 處理

Salesforce LWC學習(十) 前端處理之 list 處理

本篇參看:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array

list是我們經常要處理的內容,lwc前端針對list主要有幾個函式處理,不同函式針對不同場景有不同的功能。下面就根據幾個常用的處理list的方法進行簡單的介紹。

一. forEach

我們針對list處理經常需要迭代去處理,通常可能用到for(var index = 0;index < sampleList.length; index++)這種方式,其實我們可以直接通過forEach函式去搞定,功能以及操作和上述方式相同。有幾個引數可供選擇。

/*
(method) Array<number>.forEach(callbackfn: (value: number, index: number, array: number[]) => void, thisArg?: any): void
Performs the specified action for each element in an array.
@param callbackfn — A function that accepts up to three arguments. forEach calls the callbackfn function one time for each element in the array.
@param thisArg — An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
*/

下面通過一個demo來進行了解。

forEachSample.html:展示幾個輸入框,點選cancel以後會將所有的欄位輸入內容清空。

<template>
    <lightning-record-edit-form 
        record-id={recordId}
        object-api-name="Contact">
            <lightning-messages></lightning-messages>
            <lightning-input-field field-name="FirstName"></lightning-input-field>
            <lightning-input-field field-name="LastName"></lightning-input-field>
            <lightning-input-field field-name="Email"></lightning-input-field> 
            <lightning-input-field field-name="Phone"></lightning-input-field> 
            <div class="slds-align_absolute-center slds-p-around_medium">
                <lightning-button class="slds-m-around_xx-small" label="Cancel" onclick={handleReset}></lightning-button>
                <lightning-button class="slds-m-around_xx-small" label="Create Contact" type="submit" variant="brand" ></lightning-button>
            </div>
    </lightning-record-edit-form>
</template>

forEachSample.js:handleReset方法首先先獲取到所有的lightning-inut-field然後使用forEach,這裡只用了field,不需要用index,然後 =>方式 {}括起來去進行處理,reset是lightning-input-field的封裝的方法,感興趣的可以自行檢視,lightning-input & lightning-input-field有很多好用的方法,後期有機會可以單獨抽出來一篇部落格講解。

import { LightningElement,api } from 'lwc';

export default class ForEachSample extends LightningElement {
    @api recordId;
    handleReset(event) {
        const inputFields = this.template.querySelectorAll(
            'lightning-input-field'
        );
        if (inputFields) {
            inputFields.forEach(field => {
                field.reset();
            });
        }
     }
}

二. find & findIndex

find和findIndex在lwc中針對list處理會經常用到,用於列表針對某一個條件去查詢匹配的資料,匹配上則返回第一條匹配的資料然後終止遍歷,如果沒有匹配值則返回undefined, findIndex用於列表針對某一個條件去查詢匹配的資料,匹配上返回第一條匹配的資料的下標然後終止遍歷,下標從0開始,如果沒有匹配則返回-1.我們可以根據find / findIndex來做那種選擇列表中選擇指定一條以後顯示那條的資料資訊或者獲取那條資料詳細資訊,根據ID作為條件的遍歷。demo找的是官方的一個功能,程式碼如下:

 ContactController.cls:簡單的獲取list的列表資料

public with sharing class ContactController {
    @AuraEnabled(cacheable=true)
    public static List<Contact> getContactList() {
        return [SELECT Id, Name, Title, Phone, Email FROM Contact LIMIT 10];
    }
}

eventWithData.html:上面是一個list,點選以後觸發事件獲取到指定的那條資料然後展示在另一個區域

<template>
    <lightning-card title="EventWithData" icon-name="standard:logging">
        <template if:true={contacts.data}>
            <lightning-layout class="slds-m-around_medium">
                <lightning-layout-item>
                    <template for:each={contacts.data} for:item="contact">
                        <c-contact-list-item
                            key={contact.Id}
                            contact={contact}
                            onselect={handleSelect}
                        ></c-contact-list-item>
                    </template>
                </lightning-layout-item>
                <lightning-layout-item class="slds-m-left_medium">
                    <template if:true={selectedContact}>
                        
                        <p>{selectedContact.Name}</p>
                        <p>{selectedContact.Title}</p>
                        <p>
                            <lightning-formatted-phone
                                value={selectedContact.Phone}
                            ></lightning-formatted-phone>
                        </p>
                        <p>
                            <lightning-formatted-email
                                value={selectedContact.Email}
                            ></lightning-formatted-email>
                        </p>
                    </template>
                </lightning-layout-item>
            </lightning-layout>
        </template>

    </lightning-card>
</template>

eventWithData.js: 在handleSelect中,使用find根據ID去進行匹配,匹配後便會獲取到list中的指定的那條資料記錄。下面的console中也弄了一個findIndex的寫法。

/* eslint-disable no-console */
import { LightningElement, wire, track } from 'lwc';
import getContactList from '@salesforce/apex/ContactController.getContactList';

export default class EventWithData extends LightningElement {
    @track selectedContact;

    @wire(getContactList) contacts;

    handleSelect(event) {
        const contactId = event.detail;
        /**
         * find方法定義如下: find(predicate: (this: void, value: number, index: number, obj: number[]) => value is number, thisArg?: any)
         * array.find方法用於通過某個指定的條件去獲取滿足條件的第一個的資料,找到滿足條件的以後,後面的便不會在執行,如果遍歷沒有找到符合的則返回undefined.
         * 此函式不影響原有的array
         */
        this.selectedContact = this.contacts.data.find(
            contact => contact.Id === contactId
        );

        let datalist = [10,1,13,14];
        let result1 = datalist.findIndex(
            data => data > 20
        );
        console.log(result1);
        
    }
}

結果展示:

 三.  some & every

我們有時候會有需求為判斷當前的列表的內容是否滿足某些條件,有一個滿足內容則返回true,都不滿足返回false;或者是全部滿足返回true,有一個不滿足就返回false。這個時候就要用到some & every了。 some用於列表的內容只要有一個item滿足了條件則返回true,every為所有的都滿足才返回true,這兩個返回型別為布林型別,不影響原有的list的值。在for迴圈中使用和在函式中使用寫法可能多少有點區別,下面給一個demo用來展示寫法。需求為我們將account表中的test__c(multi picklist)展示成列表樣式來判斷某個item是否選中,程式碼如下:

someEverySample.html:列表展示multi picklist的樣式

<template>
    <table class="slds-table slds-table_cell-buffer slds-table_bordered">
        <thead>
            <tr class="slds-line-height_reset">
                <td>元件名稱</td>
                <template if:true={resultList}>
                    <template for:each={resultList} for:item="result">
                        <th class="" scope="col" key={result.label}>
                            <div class="slds-truncate">{result.label}</div>
                        </th>
                    </template>
                </template>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>是否選中</td>
                <template if:true={resultList}>
                    <template for:each={resultList} for:item="result">
                        <td key={result.label}>
                            {result.isSelected}
                        </td>
                        
                    </template>
                </template>
            </tr>
                        
        </tbody>
    </table>
</template>

someEverySample.js: result list中有針對some / every的demo以及寫法,在函式內寫法和在for迴圈中寫法多少有點區別,因為for迴圈裡面寫有一些限制。

/* eslint-disable no-console */
import { LightningElement,api,wire } from 'lwc';
import { getRecord,getFieldValue } from 'lightning/uiRecordApi';
import ACCOUNT_TEST_FIELD from '@salesforce/schema/Account.test__c';
import { getObjectInfo } from 'lightning/uiObjectInfoApi';
import ACCOUNT_OBJECT from '@salesforce/schema/Account';
import {getPicklistValues} from 'lightning/uiObjectInfoApi';

export default class SomeEverySample extends LightningElement {

    @api recordId;

    @wire(getRecord,{recordId:'$recordId',fields:ACCOUNT_TEST_FIELD})
    wiredAccount;

    @wire(getObjectInfo, { objectApiName: ACCOUNT_OBJECT })
    accountInfo;

    @wire(getPicklistValues,{ recordTypeId: '$accountInfo.data.defaultRecordTypeId', fieldApiName: ACCOUNT_TEST_FIELD })
    testList;

    get resultList() {
        if(this.wiredAccount && this.wiredAccount.data && this.testList && this.testList.data && this.testList.data.values) {
            let testFieldValueStr = getFieldValue(this.wiredAccount.data,ACCOUNT_TEST_FIELD);
            let selectedTestValues = testFieldValueStr != null ? testFieldValueStr.split(';') : [];
            let testValues = this.testList.data.values;
            let results = [];
            let res = results.some((item,index) => item > 10 && index > 0);
            let resEvery = results.every((item,index) => item > 10 && index > 0);
            console.log(res);
            console.log(resEvery);
            for(let index in testValues) {
                
                if(selectedTestValues.some(function(item,itemIndex) {
                    console.log(itemIndex);
                    return item === testValues[index].value;
                    
                }, this)) {
                    results.push({'label':testValues[index].label,'isSelected':true});
                } else {
                    results.push({'label':testValues[index].label,'isSelected':false});
                }

            }
            return results;
        }
        return [];
    }



    
}

效果展示:123/1234等值為我們Test__c表裡面的picklist values,true/false為我們在這條資料中是否選擇了相關的item。

 四. reduce

reduce用來接收一個函式作為累加器(accumulator),陣列中的每個值(從左到右)開始合併,最終為一個值.所以我們使用reduce對列表處理最終會返回一個值,要麼是布林,要麼是number等。reduce常用場景也可以檢視篇中最上面的連結去詳細檢視。

/*
(method) Array<any>.reduce(callbackfn: (previousValue: any, currentValue: any, currentIndex: number, array: any[]) => any, initialValue: any): any (+2 overloads)
        Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
        @param callbackfn — A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array.
        @param initialValue — If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
 */

我們對reduce有一個瞭解以後弄一個常用的demo來更好的消化。

reduceSample.html:展示多個輸入框,點選button去觸發一個事件處理

<template>
    <lightning-card title="LdsUpdateRecord" icon-name="standard:record">
        <div class="slds-m-around_medium">
            <template if:true={contact.data}>
                <lightning-input label="Id" disabled value={contact.data.Id}></lightning-input>
                <lightning-input label="First Name" value={contact.data.FirstName} data-field="FirstName" onchange={handleChange} class="slds-m-bottom_x-small"></lightning-input>
                <lightning-input label="Last Name" value={contact.data.LastName} data-field="LastName" onchange={handleChange} class="slds-m-bottom_x-small" required></lightning-input>
                <lightning-button label="Update Contact" variant="brand" onclick={updateContact} disabled={disabled}></lightning-button>
            </template>
            <template if:true={contact.error}>
                <!-- handle Apex error -->
            </template>
        </div>
    </lightning-card>
</template>

reduceSample.js:demo中是對lightning-input進行遍歷,如果有沒有滿足check的,則報錯,然後執行報錯的提示資訊,只有所有的都不報錯了以後才執行validation 通過的邏輯。reportValidity以及checkValidity是lightning針對Input常用的很好的自帶的方法,後期可能對Lightning input進行單獨的部落格講解,感興趣的可以自行檢視這兩個方法。我們通過reduce方法最後只返回一個true/false的值。

import { LightningElement, track, wire } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';

import getSingleContact from '@salesforce/apex/ContactController.getSingleContact';

export default class ReduceSample extends LightningElement {
    @track disabled = false;
    @track error;

    @wire(getSingleContact)
    contact;

    handleChange(event) {
         // Display field-level errors and disable button if a name field is empty.
        if (!event.target.value) {
            event.target.reportValidity();
            this.disabled = true;
        }
        else {
            this.disabled = false;
        }
    }

    updateContact() {
        let allInputList = Array.from(this.template.querySelectorAll('lightning-input'));
        /*
        方法宣告如下:
        (method) Array<any>.reduce(callbackfn: (previousValue: any, currentValue: any, currentIndex: number, array: any[]) => any, initialValue: any): any (+2 overloads)
        Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
        @param callbackfn — A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array.
        @param initialValue — If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
         */
        const allValid = allInputList.reduce((validSoFar, inputFields) => {
                inputFields.reportValidity();
                return validSoFar && inputFields.checkValidity();
            }, true);

        if (allValid) {
            //TODO success related operation
        } else {
            // The form is not valid
            this.dispatchEvent(
                new ShowToastEvent({
                    title: 'Something is wrong',
                    message: 'Check your input and try again.',
                    variant: 'error'
                })
             );
        }
    }
}

五. map & filter

map用來返回一個新陣列,不影響原有的操作的list。這個新陣列可以為這個list的每條資料針對某個條件處理以後的值,比如我們想要將一個list的裡面的每一個值都乘以5然後返回一個新的陣列,這個時候我們就可以使用map,只需要條件為對item * 5的操作即可。

filter用來使用指定的函式測試所有元素,並返回一個包含所有通過測試的元素的新陣列,此方法不影響原有的list。

這兩個基礎的意思瞭解以後,來個demo更好的瞭解一下。

mapSample.html

<template>
    <lightning-input label="Category 1" type="checkbox" onchange={handleCheckboxChange}></lightning-input>
    <lightning-input label="Category 2" type="checkbox" onchange={handleCheckboxChange}></lightning-input>
</template>

mapSample.js: 點選checkbox以後獲取選中的選項的label名稱,通過filter獲取到指定的想要資料,通過map獲取到list的變形,及我們根據規則獲取到的想要的資料。

/* eslint-disable no-console */
import { LightningElement } from 'lwc';

export default class MapSample extends LightningElement {
    handleCheckboxChange() {
        const lightningInputList = Array.from(
            this.template.querySelectorAll('lightning-input'));
        console.log(JSON.stringify(lightningInputList));
        const filters =  lightningInputList.filter(element => element.checked)
            .map(element => element.label);
        
        console.log(JSON.stringify(filters));
    }
}

總結:篇中都是lwc中針對list的常用的前端的使用方法,除了上述的方法以外還有其他的很多方法沒有列出,小夥伴們自行檢視。篇中有錯誤的地方歡迎指出,有不懂的歡迎留