elementUI的el-cascader实现省市区搜索

1. 应用场景

全国省市区级联选择器增加搜索 地级市直辖市等城市city级别的需求。即能够全选整个市
最终效果如下:
在这里插入图片描述
在这里插入图片描述

2.实现

template部分

      <el-cascader
        ref="orgRegion"
        popper-class="searchFilterPopper"
        :options="chinaJson"
        v-model="institution.region"
        :props="{ multiple: true, label: 'label', value: 'label'}"
        collapse-tags
        placeholder="地区"
        @input.native="handleInputRegion"(核心,用以监听用户输入)
        @visible-change="handleVisibleRegion($event, 'orgRegion')"
        @change="handleChangeLocation('orgRegion')"
        clearable
        filterable(开启搜索)
        >
      </el-cascader>

js部分

chinaJson: [ // 类似这样树形结构的json文件
			{
		      	"value": {
            		"value": "110000",
            		"label": "北京市",
            		"level": "province"
        		},
        		"label": "北京市",
        		"level": "province",
        		"children": [...]
			}
		],
import chinaJson from '...'
data(){
	return {
        noDistrict: [], // 没有区县的数据
      	resAllProvinceCity: [], // 所有的省市
		chinaJson,
		institution: {
			region: [], //
			lastRegion: [], // 最后传给后端的地区格式 [{city: "郑州"}]
		}
	}
},
mounted(){
	this.filterGetNoCityChildren();
},
methods:{
    handleChangeLocation(refName) {
      const { lastRegion, frontRegion } = this.getLastSelectRegion(refName);
      if (refName === 'orgRegion') {
        this.institution.lastRegion = lastRegion;
      } else {
        this.assets.lastRegion = lastRegion;
      }
      this.frontRegion = frontRegion;
    },
    // 获取最后的选中的省市区(暴力遍历...)
    getLastSelectRegion(refName) { 
   	  // 即获取到最大级别的地区数组,如全选了北京,则返回province:'北京市',
   	  // 如选中北京市海淀区,则返回 [{province: "北京市", city: "北京", district: "海淀区"}]
      let checkedNodeList = this.$refs[refName].getCheckedNodes();
      checkedNodeList = checkedNodeList.filter(item => !(item.parent && item.parent.checked));
      const lastRegion = [];
      const frontRegion = [];
      checkedNodeList.forEach((item) => {
        const { data } = item; // value
        if (data.level === 'district') {
          const parentData = item.parent.data;
          const graphParentData = item.parent.parent.data;
          lastRegion.push({
            [graphParentData.level]: graphParentData.label,
            [parentData.level]: parentData.label,
            [data.level]: data.label,
          });
        } else if (data.level === 'country') {
          lastRegion.push({ [data.level]: '中国' });
        } else {
          lastRegion.push({ [data.level]: data.label });
        }
        // frontRegion.push({ [data.level]: value }); // 原
        frontRegion.push({ [data.level]: data.value });
      });
      return {
        lastRegion, frontRegion
         // frontRegion: [{city: {value: "130500", label: "邢台", level: "city"}}]
      };
    },
     // 过滤掉city级别的所有children(来自菜鸟的暴力遍历.......求优化)
    filterGetNoCityChildren() { // deep
      const resRegion = this._.cloneDeep(this.chinaJson); // loadash
      const resAllProvinceCity = [];
      const noDistrict = resRegion.filter((province) => {
        if (province.children && province.children.length) {
          resAllProvinceCity.push(province.label);
          // eslint-disable-next-line no-param-reassign
          province.children = province.children.filter((city) => {
            if (city.children && city.children.length) {
              // eslint-disable-next-line no-param-reassign
              city.children = null;
              resAllProvinceCity.push(city.label);
            }
            return city;
          });
        }
        return province;
      });
      this.noDistrict = noDistrict;
      this.resAllProvinceCity = resAllProvinceCity;
    },

    handleInputRegion(e) { // 用户输入变化的时候修改el-cascader的数据源
      this.chinaJson = this.resAllProvinceCity.includes(e.target.value) ? this.noDistrict : chinaJson;
    },
    handleVisibleRegion(state, refName) { // 收起的时候还原数据源,并回显数据
      if (!state) {
        this.chinaJson = chinaJson;
        const resKey = refName === 'orgRegion' ? 'institution' : 'assets';
        this[resKey].region = this.filterRegionToPage(this.getLastSelectRegion(refName).lastRegion);
      }
    },
    // 回显省市区级联选择器 (菜鸟循环......求优化)
    filterRegionToPage(region) {
      if (!region || !Array.isArray(region) || !region.length) return [];
      const resRegion = [];
      region.forEach((item) => {
        if (item.country && item.country === '中国') {
          resRegion.push(['全国']);
        } else if (item.province && item.city && item.district) { // 存在县区
          resRegion.push(Object.values(item));
        } else if (!item.province && item.city && !item.district) { // city
          this.chinaJson.forEach((province) => {
            if (province.children !== null) {
              province.children.forEach((city) => {
                if (city.label === item.city) {
                  city.children.forEach((district) => {
                    resRegion.push([province.label, city.label, district.label]);
                  });
                }
              });
            }
          });
        } else { // province 直辖市同等
          const targetProvince = this.chinaJson.filter(province => item.province && item.province.includes(province.label));
          if (targetProvince.length && targetProvince[0].children !== null) {
            targetProvince[0].children.forEach((city) => {
              // eslint-disable-next-line no-unused-expressions
              if (Array.isArray(city.children)) {
                city.children.forEach((district) => {
                  resRegion.push([targetProvince[0].label, city.label, district.label]);
                });
              } else {
                resRegion.push([targetProvince[0].label, city.label]);
              }
            });
          }
        }
      });
      return resRegion;
    },
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue-ElementUI提供了一个el-cascader级联选择器组件,可以用来实现省市区三级选择器。 首先,需要引入ElementUI: ```html <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"> <script src="https://unpkg.com/vue/dist/vue.js"></script> <script src="https://unpkg.com/element-ui/lib/index.js"></script> ``` 然后,在Vue组件中使用el-cascader组件: ```html <template> <div> <el-cascader :options="options" v-model="selectedOptions" @change="handleChange"> </el-cascader> </div> </template> <script> export default { data() { return { options: [], // 省市区数据 selectedOptions: [], // 已选中的选项 }; }, mounted() { // 加载省市区数据 this.loadOptions(); }, methods: { loadOptions() { // 使用ajax加载省市区数据 // 省市区数据格式: // [ // { // value: '110000', // label: '北京市', // children: [ // { // value: '110100', // label: '市辖区', // children: [ // { // value: '110101', // label: '东城区', // }, // ... // ] // }, // ... // ] // }, // ... // ] this.options = [...省市区数据]; }, handleChange(value) { // 选项改变时触发,value为已选中的选项值 console.log(value); }, }, }; </script> ``` 其中,options是一个省市区数据的数组,selectedOptions是一个已选中的选项值的数组,handleChange方法会在选项改变时触发。 需要注意的是,el-cascader组件的options和selectedOptions属性都需要使用v-model进行双向绑定。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值