2018年sfdc工作总结_Lightning公用组件_模糊搜索单选组件

在18年下半年期间,在一个通信项目开发期间用到了不少公用组件,其中部分有自己亲身参与编码的一些成果,这里总结一下,希望能为以后积累丰富经验,如果有不合理的地方也欢迎各位评论指正。

模糊搜索单选组件,包括:
Aura:
AutoMatchPickList
SearchInput
CommonEvent.evt
AutoMatchListEvt.evt
Apex:
AutoMatchPickListCtl.cls


AutoMatchPickList.cmp

<!--
 -
 - 这是具有相似查询功能的搜索框组件
 -
 - @return {string} value - 通过comp.get('v.value')获得最终选择的值
 -->

<aura:component controller="AutoMatchPickListCtl" access="global">
    <!-- 需要查找的对象 -->
    <aura:attribute name="objectType" type="String" default="" required="true"/>

    <!-- 需要模糊匹配的字段名称 -->
    <aura:attribute name="fieldList" type="String" default="" required="true"/>

    <!-- 需要显示在下拉框中作为标签的字段 -->
    <aura:attribute name="labelField" type="String" default="" required="true"/>

    <!-- 查询过滤条件 -->
    <aura:attribute name="filterCondition" type="String" default=""/>
    <aura:attribute name="isMatch" type="Boolean" default="true"/>
    <aura:attribute name="label" type="String" default=""/>
    <aura:attribute name="disabled" type="Boolean" default="false"/>
    <aura:attribute name="placeholder" type="String" default=""/>
    <aura:attribute name="required" type="Boolean" default="false"/>

    <aura:attribute name="options" type="List" default="[]"/>
    <aura:attribute name="inputValue" type="String" default=""/>

    <aura:attribute name="class" type="String" default=""/>

    <!--通过该属性可以获得最终选择的值,-->
    <aura:attribute name="value" type="String" default=""/>    

    <!--通过该回掉函数也可以获得最终选择的值-->
    <aura:attribute name="onSelect" type="Aura.action" default="{!c.emptyAction}"/>
    <!--input行内样式 create by eric -->
    <aura:attribute name="inputClass" type="String" default=""/>

    <!--手动实现表单验证相关的方法-->
    <aura:method name="checkValidity"/>
    <aura:method name="reportValidity"/>

    <aura:attribute name="scopefilter" type="String" default="" />

    <aura:handler action="{!c.init}" name="init" value="{!this}" />
    <!-- 动态传入条件时,重新执行 init  -->
    <aura:handler action="{!c.init}" name="change" value="{!v.filterCondition}" />

    <c:SearchInput class="{!v.class}" aura:id="searchInput" required="{!v.required}" disabled="{!v.disabled}" label="{!v.label}" value="{!v.value}" options="{!v.options}" onSearch="{!c.handleSearch}" onSelect="{!v.onSelect}" placeholder="{!v.placeholder}" inputValue="{!v.inputValue}" isMatch="{!v.isMatch}" inputClass="{!v.inputClass}"/>

</aura:component>

AutoMatchPickListController.js

({
    handleSearch:function(comp,event,helper)
    {
        var data=event.getParam('data');
        var searchValue=data.value;
        
        //调用服务器接口
        var action = comp.get("c.returnPicklistItemMap");
        action.setParams({
            searchValue:searchValue,
            objectType:comp.get('v.objectType'),
            fieldlist:comp.get('v.fieldList'),
            filterCondition:comp.get('v.filterCondition'),
            labelField:comp.get('v.labelField'),
            scopeCondtion:comp.get('v.scopefilter')
        });
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
                // Alert the user with the value returned
                // from the server
                var returnValue=response.getReturnValue();
                var options=JSON.parse(returnValue);
                comp.set('v.options',options);
            }
            else if (state === "INCOMPLETE") {

            }
            else if (state === "ERROR") {

            }
        });

        $A.enqueueAction(action);
    },
    init:function(comp,event,helper)
    {   
        //调用服务器接口
        var action = comp.get("c.returnPicklistItemMap");
        action.setParams({
            searchValue:'',
            objectType:comp.get('v.objectType'),
            fieldlist:comp.get('v.fieldList'),
            filterCondition:comp.get('v.filterCondition'),
            labelField:comp.get('v.labelField')
        });

        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
                // Alert the user with the value returned
                // from the server
                var returnValue=response.getReturnValue();
                var options=JSON.parse(returnValue);
                comp.set('v.options',options);
            }
        });

        $A.enqueueAction(action);
    },
    //空的action,作为onSelect的默认值,最优?
    emptyAction:function(comp,event,helper)
    {
        // console.log('On input--->'+comp.get('v.inputValue'));
        // console.log('on options--->'+JSON.stringify(comp.get('v.options')));
    },
    checkValidity: function(comp, event, helper) {
        var isValidity = comp.find('searchInput').checkValidity();
        if(isValidity){
            var isRequired = comp.get('v.required');
            var inputValue = comp.get('v.value');
            if(isRequired && 
                (inputValue == null || inputValue == undefined || inputValue == '')){
                isValidity = false;
            }
        }

        return isValidity;

        // return comp.find('searchInput').checkValidity();
    },
    reportValidity: function(comp, event, helper) {
        comp.find('searchInput').reportValidity();    
    }
})

AutoMatchPickListCtl.cls

public without sharing class AutoMatchPickListCtl {
    
    /*接口入参:
    String searchValue,  
    String objectType,
    List<String> fieldlist  
    filterCondition:Sample[{"FieldName": "LastName","Condition": "=","Value": "Ray"}]*/
    @AuraEnabled
    public static String returnPicklistItemMap(String searchValue, String objectType, String fieldlist, String filterCondition, String labelField,String scopeCondtion) {

        List<SelectItem> returnPickList = new List<SelectItem>();
        String searchquery = '';
        System.debug(LoggingLevel.INFO, '*** searchValue: ' + searchValue);

        // Search query by specific
       if (String.isNotBlank(searchValue)) {
            searchquery='FIND {1} IN ALL FIELDS RETURNING {2} ({3}{4})';
            searchValue = '\'*' + searchValue + '*\'';
            searchquery = searchquery.replace('{1}', searchValue);
            searchquery = searchquery.replace('{2}', objectType);
            searchquery = searchquery.replace('{3}', fieldlist);
            searchquery = searchquery.replace('{4}', generateCondition(filterCondition,scopeCondtion));
            System.debug(LoggingLevel.INFO, '*** searchquery: ' + searchquery);
            List<List<SObject>>searchList=search.query(searchquery);
            if (searchList.size() > 0) {
                List<SObject> oblist = searchList[0];
                for (SObject sobj : oblist) {
                    SelectItem pitem = new SelectItem();
                    pitem.label = (String)sobj.get(labelField);
                    pitem.value = (String)sobj.get('Id');
                    if (String.isNotBlank(pitem.label)) {
                        returnPickList.add(pitem);
                    }
                }
            }
        }

        // Setting Defalult select result
        if (String.isBlank(searchValue)) {
            searchquery='SELECT {1} FROM {2} {3}';
            searchquery = searchquery.replace('{1}', fieldlist);
            searchquery = searchquery.replace('{2}', objectType);
            searchquery = searchquery.replace('{3}', generateCondition(filterCondition,scopeCondtion));
            searchquery =  searchquery + (' limit 100');
            System.debug(LoggingLevel.INFO, '*** searchquery: ' + searchquery);
            List<SObject> sobjectlist = Database.query(searchquery);
            if (sobjectlist.size() > 0) {
               for (SObject sobj : sobjectlist) {
                    SelectItem pitem = new SelectItem();
                    pitem.label = (String)sobj.get(labelField);
                    pitem.value = (String)sobj.get('Id');
                    if (String.isNotBlank(pitem.label)) {
                        returnPickList.add(pitem);
                    }
                } 
            }
        }
        return JSON.serialize(returnPickList);
    }

    public static String generateCondition(String filterCondition, String scopeCondtion) {
        System.debug(LoggingLevel.INFO, '*** filterCondition: ' + filterCondition);
        System.debug(LoggingLevel.INFO, '*** scopeCondtion: ' + scopeCondtion);
        if (String.isNotBlank(filterCondition)) {
            List<Condtion> condtions = (List<Condtion>)JSON.deserialize(filterCondition, List<Condtion>.class);

            if (String.isNotBlank(scopeCondtion)) {
                List<Condtion> condtions2 = (List<Condtion>)JSON.deserialize(scopeCondtion, List<Condtion>.class);
                condtions.addAll(condtions2);
            }
            String returnFitler = ' WHERE ';
            Integer i=1;
            for (Condtion con : condtions) {
                if (i>1) {
                    returnFitler += ' And';
                }
                if (con.Condtion != 'IN' && con.Value!='true') {
                    returnFitler += (' ' + con.FieldName +' ' + con.Condtion + ' \''+ con.Value +'\'' + ' ');
                }else if(con.Value=='true'){
                    returnFitler += (' ' + con.FieldName +' ' + con.Condtion + Boolean.valueOf(con.Value) + ' ');
                }else {
                    returnFitler += (' ' + con.FieldName +' ' + con.Condtion + ' '+ con.Value.replace('"',  '\'') +' ' + ' ');
                }
                
                i++;
            }
            return returnFitler;
        }
        
        return '';
    }

    public class Condtion {
        public String FieldName {get; set;}
        public String Condtion {get; set;}
        public String Value {get;set;}
    }
     public class SelectItem {
        @AuraEnabled public String label;
        @AuraEnabled public String value;
    }    
}

SearchInput.cmp

<!--
 -
 - 公共的搜索框组件
 -
 - @param {string} label
 -
 - @param {boolean} disabled
 -
 - @param {string} placeholder
 -
 - @param {array} options       - 搜索到的选项列表,
 -     格式1:[{label:'中国',value:'zh'},{label:'法国',value:'fr'}]
 -     格式2:['中国','法国'],此时label和value的值一样
 -
 - @param {function} onSearch   - 输入搜索时触发
 -
 - @param {function} onSelect   - 选中值时触发
 -
 - @return {string} value       - 通过comp.get('v.value')获得最终选择值
 -->

<aura:component description="SearchInput">
    <aura:attribute name="label" type="String" default=""/>
    <aura:attribute name="disabled" type="Boolean" default="false"/>
    <aura:attribute name="placeholder" type="String" default=""/>
    <aura:attribute name="options" type="List" default="[]"/>
    <aura:attribute name="required" type="Boolean" default="false"/>
    <aura:attribute name="class" type="String" default=""/>

    <!--input的值-->
    <aura:attribute name="inputValue" type="String" default=""/>
    <!--最终选择的值,和input的值不一样,返回的是value不是label-->
    <aura:attribute name="value" type="String" default=""/>

    <!--下拉列表是否可见-->
    <aura:attribute name="selectVisible" type="Boolean" default="false"/>
    <!--是否正在查询-->
    <aura:attribute name="isSearching" type="Boolean" default="false"/>
    <aura:attribute name="isMatch" type="Boolean" default="true"/>

    <!--input行内样式 -->
    <aura:attribute name="inputClass" type="String" default=""/>

    <aura:registerEvent name="onSearch" type="c:CommonEvent"/>
    <aura:registerEvent name="onSelect" type="c:CommonEvent"/>
    <aura:registerEvent name="relatedAffect" type="c:AutoMatchListEvt"/>
    
    <aura:handler name="init" value="{!this}" action="{!c.init}"/>
    <aura:handler name="change" value="{!v.options}" action="{!c.optionsUpdated}"/>


    <!--手动实现表单验证相关的方法-->
    <aura:method name="checkValidity"/>
    <aura:method name="reportValidity"/>

    <div class="{!v.class}">
        <form class="search-input__form" autocomplete="false" onsubmit="{!c.preventDefault}">
            <lightning:input aura:id="input" required="{!v.required}" type="text" label="{!v.label}" disabled="{!v.disabled}"
                         isLoading="{!v.isSearching}" class="{!v.inputClass}"
                         placeholder="{!v.placeholder}" value="{!v.inputValue}" onfocus="{!c.handleFocus}"
                         onchange="{!c.changeInputValue}" onblur="{!c.handleBlur}"/>
            <lightning:icon iconName="utility:search" size="xx-small"/> 
        </form>

        <aura:if isTrue="{!v.options.length > 0}">
            <ul onmousedown="{!c.selectOption}" style="{!'display:'+(v.selectVisible?'block':'none')}">
                <aura:iteration items="{!v.options}" var="option">
                    <!--将onclick事件换成onmousedown事件,以消除input的onblur触发时,layout变化,导致li的onclick无法正常侦听的问题-->
                    <li data-value="{! option.value!=undefined?option.value:option}" role="option" aria-selected="true">
                        {! option.label!=undefined?option.label:option}
                    </li>
                </aura:iteration>
            </ul>
        </aura:if>
    </div>
</aura:component>

SearchInput.css

.THIS {
    position: relative;
}

.THIS ul
{
    max-height: 10rem;
    overflow-y: auto;
    border: 1px solid rgb(217, 219, 221);
    background-color: #fff;
    cursor: pointer;
    width: 100%;
    position: absolute;
    left: 0;
    z-index: 99;/*因为后台页面的header的z-index为100,为了避免滚动时叠在UI上,现在将z-index的值改成99*/  
}
.THIS .label-input{
    display: inline-block;
    margin-left: 9px;
}
.THIS .label-box{
    margin-bottom: 5px;
}
.THIS li
{
    line-height: 2rem;
    text-align: center;
}

.THIS li:hover
{
    background-color: #eeeeee;
}

/*当disable时,手动移除输入框的清除按钮*/
.THIS input[disabled] ~ div
{
    display: none;
}


/*假的search按钮的样式*/
.THIS lightning-icon
{
    position: absolute;
    left: 0.75rem;
    top: 1.8rem;
}


.THIS lightning-icon svg
{
    fill: rgb(171, 173, 176);
}

.THIS lightning-input input
{
    padding-left: 2rem;
}

SearchInputController.js

({
    //尝试根据options和value确定inputValue
    init:function(comp,event,helper)
    {
        console.log('初始value',comp.get('v.value'));
        helper.getInputValue(comp);
    },
    optionsUpdated:function(comp,event,helper)
    {
        comp.set('v.isSearching', false);
        helper.getInputValue(comp);
    },
    selectOption:function(comp,event,helper)
    {
        var li=event.target;
        //确定是li标签
        if(li.tagName==='LI')
        {
            var label=li.textContent;
            var value=li.getAttribute('data-value');

            //更新inputValue
            comp.set('v.inputValue',label);
            //更新value
            comp.set('v.value',value);
            comp.set('v.selectVisible',false);

            helper.fireEvent(comp,'onSelect','v.value');

            var evt = $A.get("e.c:AutoMatchListEvt");
            evt.fire();
        }
        //点击的scrollbar
        if(li.tagName==='UL')
        {
            helper.clickScrollbar=true;
        }
    },
    handleFocus:function(comp,event,helper)
    {
        comp.set('v.selectVisible',true);
    },
    changeInputValue:function(comp,event,helper)
    {
        //只要触发onChange,最终选择的值,重置为空
        comp.set('v.value','');
        comp.set('v.isSearching', true);
        comp.set('v.selectVisible',true);

        //onSelect回传v.value的值
        helper.fireEvent(comp,'onSelect','v.value');

        //onSearch回传v.inputValue的频率降低,将id挂靠到comp上,也可以挂靠到helper上(ie上不要使用箭头函数!)
        var delay = 400;
        //第一次立即执行
        if (comp.id === undefined) {
          helper.fireEvent(comp,'onSearch','v.inputValue');

          comp.id = setTimeout(function(){
            comp.id = undefined;
          }, delay);
        } else {
          clearTimeout(comp.id);

          comp.id = setTimeout(function(){
            helper.fireEvent(comp,'onSearch','v.inputValue');
            //为下一次立即执行做准备
            comp.id = undefined;
          }, delay);
        }
    },
    handleBlur:function(comp,event,helper)
    {
        //如果是点击的scrollbar触发的input的blur事件,不认可
        if(helper.clickScrollbar===true){
            helper.clickScrollbar=false;
            return;
        }

        //input失去焦点时,有可能是在选择下拉列表项,现在li侦听的是mousedown,与blur事件不冲突
        comp.set('v.selectVisible',false);//accesss设置成private后,这段代码不起作用?        
        comp.reportValidity();        

        if (comp.get("v.inputValue") == '' || comp.get("v.inputValue") == null) {
            var evt = $A.get("e.c:AutoMatchListEvt");
            evt.fire();
        }
    },    
    checkValidity:function(comp, event, helper) {
        var b=true;

        var selected=true;     
        if(comp.get('v.required'))
        {
            selected=false;                
            var value=comp.get('v.value');
            var inputValue=comp.get('v.inputValue');
            var options=comp.get('v.options');
            //有可选数据,disable状态下,数据有时候并不全
            if(options)
            {
                //确保inputValue和value匹配,是从可选数据里选出来的
                for(var i=0,len=options.length;i<len;i++)
                {
                    var option=options[i];
                    var _value=option.value===undefined?option:option.value;
                    var _inputValue=option.label===undefined?option:option.label;
                    //不用===做判断,
                    if(value==_value&&inputValue==_inputValue)
                    {
                        selected=true;
                        break;                        
                    }
                }
            }
            //再做一次判断
            if(!selected)
            {
                if(value!=='')
                {
                    selected=true;
                }                
            }
            b=selected;
        }

        comp.set('v.isMatch', selected);
        return b;
    },
    reportValidity: function(comp, event, helper) { 
        var input=comp.find('input');
        if(comp.checkValidity())
        {
            input.setCustomValidity('');                                
        }
        else
        {            
            var disabled=comp.get('v.disabled');            
            if(!disabled)//fixed ie problem: show customValidity even disabled
            {
                input.setCustomValidity('您输入的值不正确,请从下拉列表中选择一个值。');
            }
        }
        input.reportValidity();
    },
    preventDefault : function(component, event){
        event.preventDefault();
    }
})

SearchInputHelper.js

({
    fireEvent:function(comp,eventType,valueKey)
    {
        //获得值
        var value=comp.get(valueKey);
        //获得事件
        var event=comp.getEvent(eventType);
        //值设置为事件的参数
        event.setParams({
            type:eventType,
            data:{
                value:value
            }
        });
        //发射
        event.fire();
    },
    /*
    * 获取初始inputValue
    */
    getInputValue:function(comp)
    {
        var options=comp.get('v.options');
        if(Array.isArray(options))
        {
            var value=comp.get('v.value');
            var inputValue=comp.get('v.inputValue');
            //value有效
            if(this.isValidString(value))
            {                
                for(var i=0,len=options.length;i<len;i++)
                {
                    var option=options[i];
                    var _value=option.value===undefined?option:option.value;
                    var _label=option.label===undefined?option:option.label;
                    if(value===_value)
                    {
                        if(inputValue!==_label)
                        {
                            console.log('searchinput设置inputvalue初始值');
                            comp.set('v.inputValue',_label);
                            break;                         
                        }
                                              
                    }
                }                
            }            
        }  
    },
    isValidString:function(str)
    {
        return str!==undefined&&str!==null&&str!=='';
    }
})

CommonEvent.evt

<aura:event type="APPLICATION" description="Event template" >
	<aura:attribute name="type" type="String"/>
	<aura:attribute name="message" type="String"/>
	<aura:attribute name="data" type="Object"/>
</aura:event>

AutoMatchListEvt.evt

<aura:event type="APPLICATION" description="Event template" >
    <aura:attribute name="Type" type="String" default="Country"/>
    <aura:attribute name="ParentID" type="String" default=""/>
</aura:event>

引用组件示例:

<aura:attribute name="searchName" type="String" default=""/>
<aura:attribute name="returnResult" type="String" default=""/>
<c:AutoMatchPickList objectType="Account" 
                     labelField="Name" 
                     filterCondition=''
                     fieldList="Name"
                     value="{! v.returnResult}"
                     placeholder="Please input"
                     label="Search Account"
                     required="true"
                     aura:id="account-search"
                     inputValue="{! v.searchName}" />

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值