在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 的执行顺序问题以及提出如何解决此种问题的方案,知识点很简单,纯粹前端知识,篇中有错误地方欢迎指出,有不懂欢迎留言。