先上效果图:

element表格搜索 elementui的select搜索多选_vue下拉框分组

element表格搜索 elementui的select搜索多选_vue拼音转汉字_02

这个功能实现起来其实不是很难,主要有几处细节需要注意

1,vue中js模块的导出

2,linq的使用

3,一级分组和二级分组的业务逻辑处理

主要实现步骤如下:

一:准备linq

1,安装linq。

npm install linq

2,在main.js中引用

import linq from 'linq';
Vue.prototype.Enumerable=linq;

3,对linq的理解。个人觉得跟Java8中的stream操作较像,具体使用可以百度到

二:template页面

<el-form-item v-if="editDailogFormType=='region'" label="需求省份" prop="channelName">
                    <el-select v-model="regionConfigForm.citys" placeholder="请选择区域"
                               multiple
                               filterable
                               remote
                               reserve-keyword
                               :remote-method="(queryString)=>{remoteMethod(queryString);}"
                               style="width: 100%;">
                        <el-option-group
                                v-for="group in multipleSelectOption"
                                :key="group.province"
                                :label="group.province"
                                @click.native="checkProvince(group.province)">
                            <el-option
                                    v-for="item in group.city"
                                    :key="item.value"
                                    :label="item.city_name"
                                    :value="item.city_name">
                            </el-option>
                        </el-option-group>
                    </el-select>
</el-form-item>

  画蛇添足地解释一下el-select下拉框的这些个属性

multipe:开启多选
filterable:开启搜索
remote:开启远程搜索
reserve-keyword:关键词
:remote-method:远程搜索触发的方法。
el-select下的el-option-group是分组名(如省份),el-option是分组下面的具体选项(如城市)。
@click.native是点击分组名时触发的方法。

三:

1,json数据的准备,我的json格式是[{province:xxx,city:[{city_name:xxx}]}]这种格式的。

由于省市是静态资源,我可以做成json文件,如果是动态资源,可以请求后台接口,从后台中获取数据。

2,拼音相关的js。

常用的js方法都写在下面了,细心的话可能已经发现,下方代码中的pinyin这个全局变量只定义了一个拼音。这个pinyin变量是个json格式的字符串,实在是太长了,太占篇幅,影响阅读。

包含了汉字转拼音,提取首拼,汉字、全拼、首拼的比较和包含方法。

具体操作:创建一个名为pinYinForVue的js文件。把以下内容copy进去

export const pinyin = {
    'a': '\u554a\u963f\u9515',
}
export default {

    arraySearch: function (l1, l2) {
        for (let name in pinyin) {
            if (pinyin[name].indexOf(l1) !== -1) {
                return this.ucfirst(name)
            }
        }
        return false
    },
    ucfirst: function (l1) {
        if (l1.length > 0) {
            let first = l1.substr(0, 1).toUpperCase();
            let spare = l1.substr(1, l1.length);
            return first + spare
        }
    },
    /*获取首字母*/
    getInitials: function (text) {
        let pinyin="";
        for (let i = 0; i < text.length; i++) {
            pinyin=pinyin+this.convertToPinYin(text[i])[0];
        }
        return pinyin; //若取拼音,则返回 pinyin
    },

    /*判断text中是否包含key,通过汉字、拼音、首拼判断*/
    wordInclude:function (text,key) {
        if(this.convertToPinYin(text).toLowerCase().indexOf(key) != -1||//全拼是否包含
            this.convertToPinYin(text).indexOf(key) != -1 ||//全拼转小写是否包含
            this.getInitials(text).toLowerCase().indexOf(key) != -1||//首拼是否包含
            this.getInitials(text).indexOf(key) != -1 ||//首拼转小写是否包含
            text.indexOf(key) != -1 //汉字是否包含
        ){
           return true;
        }else{
            return false;
        }
    },
    /*这个转拼音的方法可以单独拿出去用(更灵活),也可以在下方的wordInclude中被调用*/
    convertToPinYin: function (l1) {
        let l2 = l1.length;
        let I1 = '';
        let reg = new RegExp('[a-zA-Z0-9]');
        for (let i = 0; i < l2; i++) {
            let val = l1.substr(i, 1);
            let name = this.arraySearch(val, pinyin);
            if (reg.test(val)) {
                I1 += val
            } else if (name !== false) {
                I1 += name
            }
        }
        I1 = I1.replace(/ /g, '-');
        while (I1.indexOf('--') > 0) {
            I1 = I1.replace('--', '-')
        }
        return I1
    },
}

3,调用

这个注释是我写的最详细的一次
import pinyin  from '../../utils/pinYinForVue'
import cityjson from '../../assets/city'

export default {
   data(){
        return {
            regionConfigForm:{
                    citys:[]
            }
            multipleSelectOption:cityjson,
        }
   },
   methods: {
        remoteMethod(queryString) {
                /*json中的一级分组是省份,二级分组是城市*/
                this.multipleSelectOption=cityjson;
                /*去掉重复key,linq中的distinct,where,select 类似Java8的stream流操作*/
                this.multipleSelectOption=this.Enumerable.from(this.multipleSelectOption).distinct("o=>o.province").toArray();
                /*遍历所有省份数据,根据输入框中的值对所有的一级分组过滤,保留符合条件的数据再重新组装成list*/
                let parentSearchList=this.Enumerable.from(this.multipleSelectOption).where((data)=>{
                    let jsonHasQueryString=false;
                    /*如果省份的汉字、全拼、首拼是否包含输入的值*/
                    if(pinyin.wordInclude(data.province,queryString)){
                        jsonHasQueryString=true;
                    }
                    return jsonHasQueryString;
                }).toArray();

                let childSearchList=[];
                /*遍历所有城市数据,根据json数据结构先遍历省份,再遍历省份下城市。*/
                for(let i=0;i<this.multipleSelectOption.length;i++){
                    let parentItem=this.multipleSelectOption[i];
                    for(let j=0;j<parentItem.city.length;j++){
                        let childName=parentItem.city[j].city_name;
                        /*如果城市的汉字、全拼、首拼是否包含输入的值*/
                        if(pinyin.wordInclude(childName,queryString)){
                            childSearchList.push({province:parentItem.province,city:[{city_name:childName}]});
                        }
                    }
                }
                /*合并一级分组和二级分组的值,比如 输入 “hb”,
                会出现一级分组“河北”及下属的多个二级城市,也会出现 单独的二级分组“淮北”以及所属的一级省份“安徽”*/
                let nowmultipleSelectOption =parentSearchList.concat(childSearchList);
                /*去掉key相同的重复数据,key相同虽然不影响使用,但控制台会报红*/
                this.multipleSelectOption = this.Enumerable.from(nowmultipleSelectOption).distinct("o=>o.province").toArray();
            },
            /*一级分组名点击全选*/
            checkProvince(province){
                /*定义一个临时数组*/
                let addProvinceCitys= [];
                /*这个for循环是为了实现点击一级分组全部勾选的功能*/
                for(let i=0;i<cityjson.length;i++){
                    /*遍历所有省份*/
                    let parentItem=cityjson[i];
                    if(parentItem.province==province){
                        /*若省份能跟此次点击的省份匹配,遍历城市*/
                        for(let j=0;j<parentItem.city.length;j++){
                            /*获取已选中元素中是否包含 此次省份下的城市,如果不包含则添加到临时数组中*/
                            let childName=parentItem.city[j].city_name;
                            let index=this.regionConfigForm.citys.indexOf(childName);
                            if(index==-1){
                                addProvinceCitys.push(childName);
                            }
                        }
                    }
                }
                /*其实还想做一个反选功能的,但思路暂时还没捋顺,以后再补充*/
                /*将临时数组中合并到下拉框的已选择数组中,即可完成赋值选中*/
                this.regionConfigForm.citys = this.regionConfigForm.citys.concat(addProvinceCitys);
            },
   }
}

over。