在Salesforce LWC學習(八) Look Up組件實現篇中,我們實現了公用的lookup組件,使用的過程中,會發現當我們輸入內容以后,搜索出來的列表便無法被清空。
針對此種情況我們打算優化一下代碼,針對前端的輸入框,增加onblur函數,當鼠標移除情況下,設置searchTerm為空字符串並且不讓下方的options展示,當鼠標移入或者輸入內容情況下在展示下方的options.
customLookUpForLwc.html:輸入框添加onblur,下方options使用變量控制顯隱
<template> <div> <div class="slds-form-element"> <div class="slds-form-element__control"> <div class="slds-combobox_container"> <div id="box" class={boxClass} aria-expanded="true" aria-haspopup="listbox" role="combobox"> {searchLabel} <div class="slds-combobox__form-element slds-input-has-icon slds-input-has-icon_right" role="none"> <template if:true={isValue}> <div id="lookup-pill" class="slds-pill-container"> <lightning-pill class="pillSize" label={valueObj} name={valueObj} onremove={handleRemovePill}> <lightning-icon icon-name={iconName} alternative-text="acc" ></lightning-icon> </lightning-pill> </div> </template> <template if:false={isValue}> <div class="slds-p-top_none"> <lightning-input class={inputClass} type="search" id="input" value={searchTerm} onclick={handleClick} onchange={onChange} onblur={handleBlurEvent} variant="label-hidden" autocomplete="off" placeholder="Search..." label='account search'> </lightning-input> </div> </template> </div> <template if:true={isEnableShowOptions}> <div id="listbox-id-1" class="slds-dropdown slds-dropdown_length-with-icon-7 slds-dropdown_fluid" role="listbox"> <ul class="slds-listbox slds-listbox_vertical" role="presentation"> <template for:each={options} for:item="item"> <li key={item.Id} onclick={onSelect} data-id={item.Id} role="presentation"> <span class="slds-lookup__item-action slds-lookup__item-action--label" role="option"> <lightning-icon class="slds-icon slds-icon--small slds-icon-text-default" icon-name={iconName} alternative-text={objName} size="small"></lightning-icon> <span class="slds-truncate">{item.Name}</span> </span> </li> </template> </ul> </div> </template> </div> </div> </div> </div> </div> </template>
customLookUpForLwc.js:搜索結果處增加處理項,同時增加是否顯隱標簽的判斷邏輯
/* eslint-disable no-console */ /* eslint-disable @lwc/lwc/no-async-operation */ import lookUp from '@salesforce/apex/CustomLookUpForLwcController.lookUp'; import { getObjectInfo } from 'lightning/uiObjectInfoApi'; import { getRecord } from 'lightning/uiRecordApi'; import { api, LightningElement, track, wire } from 'lwc'; export default class CustomLookUpForLwc extends LightningElement { //store object record id @api valueId; //record API name @api objName; //record icon name,see Lightning Design System to choose @api iconName; @api filter = ''; //unique key used to mark the unique component. several component use this component need to mapping @api uniqueKey; //used to set the field to fetch.eg: ['Account.Name'] means we need to search account name field as filter @api fields; //search label show in lookup component @api searchLabel; @track searchTerm = ''; //record name value @track valueObj; //record href @track href; //fetch result @track options; //fetch result backup @track optionsBackup; //is available value to show in lightning-pill @track isValue = false; //indicator if enable show options @track isEnableShowOptions = true; //css @track boxClass = 'slds-combobox slds-dropdown-trigger slds-dropdown-trigger_click slds-has-focus'; @track inputClass = ''; @wire(lookUp, {searchTerm : '$searchTerm', myObject : '$objName', filter : '$filter'}) wiredRecords({ error, data }) { if (data) { this.record = data; this.error = undefined; if(this.searchTerm && this.isEnableShowOptions) { this.options = this.record; } else if(this.isEnableShowOptions) { if(!this.optionsBackup) { this.optionsBackup = this.record; } this.options = this.optionsBackup; } } else if (error) { this.error = error; this.record = undefined; } } //To get preselected or selected record @wire(getRecord, { recordId: '$valueId', fields: '$fields' }) wiredOptions({ error, data }) { if (data) { this.record = data; this.error = undefined; this.valueObj = this.record.fields.Name.value; this.href = '/'+this.record.id; this.isValue = true; } else if (error) { this.error = error; this.record = undefined; } } handleClick() { this.searchTerm = ''; this.isEnableShowOptions = true; this.inputClass = 'slds-has-focus'; this.boxClass = 'slds-combobox slds-dropdown-trigger slds-dropdown-trigger_click slds-has-focus slds-is-open'; } onSelect(event) { console.log("In onSelect"); let ele = event.currentTarget; let selectedId = ele.dataset.id; //As a best practise sending selected value to parent and inreturn parent sends the value to @api valueId let key = this.uniqueKey; const valueSelectedEvent = new CustomEvent('valueselect', { detail: { selectedId, key }, }); this.dispatchEvent(valueSelectedEvent); this.boxClass = 'slds-combobox slds-dropdown-trigger slds-dropdown-trigger_click slds-has-focus'; } onChange(event) { this.searchTerm = event.target.value; this.isEnableShowOptions = true; } handleBlurEvent() { this.isEnableShowOptions = false; this.searchTerm = ''; } handleRemovePill() { this.isValue = false; let selectedId = ''; let key = this.uniqueKey; const valueSelectedEvent = new CustomEvent('valueselect', { detail: { selectedId, key }, }); this.dispatchEvent(valueSelectedEvent); } }
我們修改以后運行結果為:當我們輸入內容onblur失去焦點時,確實實現了下方內容隱藏,但是當我們輸入內容有結果選中下方item時,item也並沒有選中而是同樣出現了下方內容隱藏的效果。這個是什么原因呢?
這個時候需要考慮的一點就是標准事件的執行順序問題,標准事件中,我們常用的有 onclick / onblur,大家都知道onclick 是按鈕按壓以后執行,onblur是元素失去焦點以后執行。相當於onclick 為 onmousedown -> onmouseup這兩個操作以后作為onclick,onblur在onmousedown以后,但是在onmouseup以前,也就是說Onblur在onclick操作以前,所以上述的demo中,下面的ul li的onclick事件無法調用到只能調用到input的onblur的事件,針對這種情況我們最終只需要將li的事件從onclick 修改成onmousedown即可完美的解決上述的問題。
總結:篇中主要是通過優化共通方法來引出 onclick / onblur 的執行順序問題以及提出如何解決此種問題的方案,知識點很簡單,純粹前端知識,篇中有錯誤地方歡迎指出,有不懂歡迎留言。