elementUI's el-cascader implements province and city search

1. Application scenarios

The nationwide province-city cascade selector increases the demand for city-level cities such as prefecture 搜索 -level cities and municipalities directly under the Central Government. That is, you can select the entire city.
The final effect is as follows:
Insert image description here
Insert image description here

2. Realize

template part

      <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 part

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;
    },
}

Guess you like

Origin blog.csdn.net/s18438610353/article/details/125912487