注:公司領導要求封裝一個區划選擇器,最大支持五級區划,並且適用的場景有很多:數據全部由接口所得並且是懶加載形式;能夠回顯當前登錄賬號所屬級別的默認地址;還能夠回顯接口返回的默認地址;能夠配置區划選擇器的最大級別;禁止當前級別之前的地址被選擇等等功能,花了兩天的事時間,終於算是完善優化好了,供大家一起參考,代碼若有缺陷還望指針,感謝!以下是源代碼:
特別說明:這里面使用懶加載形式調取接口,每次接口返回一個級別的數據,如第一次默認返回所有省級,點擊安徽省,傳安徽省code則再次調用接口返回安徽省下所有地級市的數據,依次類推;這里接口返回的數組中,必須要有的參數:[{name:'級別名稱',id:'級別code值'}]
技術棧:VUE+ElementUI
組件areaCascader.vue
<template> <div> <el-tooltip effect="dark" :content="addressName" placement="top" :enterable="false" :disabled="disabled" > <el-cascader :disabled="casDisabled" :clearable="clearable" ref="areaSelect" v-model="areaCodeList" :props="belongRegoinProps" :options="belongRegoinOptions" placeholder="請選擇" @change="belongRegionChange" @visible-change="visibleChange" style="width: 100%" > </el-cascader> </el-tooltip> </div> </template> <script>
// 這里是我項目中自己封裝的get請求 各位可自己封裝 import { get } from "@/apis/apicommon"; export default { name: "areaCascader", components: {}, // 注意:isCurrentOrgDefaultArea與isPortDefaultArea不能同時為true props: { setLevel:{ type:Number, default:5 }, // true開啟默認回顯當前賬號所屬區划地址,為false時關閉回顯並且可選擇任意區划 isCurrentOrgDefaultArea: { type: Boolean, default: true, }, // 回顯指定區划地址的對象數據,必須為以下指定格式字段,切且注意該對象傳入時間必須在該組件初始化之前 defaultAddressInfos: { type: Object, // default:{ // addressName:"", // provinceCode:"", // cityCode:"", // countyCode:"", // streetCode:"", // communityCode:"", // level:"" // } }, // true開啟默認回顯指定區划地址,需必傳對象defaultAddressInfos,且與isCurrentOrgDefaultArea不能同時為true isPortDefaultArea: { type: Boolean, default: false, }, // 是否可清空已選,默認不可清空 clearable: { type: Boolean, default: false, }, casDisabled: { type: Boolean, default:false }, }, watch: {}, data() { const self = this; return { disabled: true, addressName: "", defaultHosuse: { province: "", city: "", area: "", town: "", vill: "", }, CurrentOrg: {}, currentLastLevelCode: "", CurrentLevel: Number, areaCodeList: [], currentOrgLevel: "", belongRegoinOptions: [], belongRegoinProps: { checkStrictly: true, lazy: true, lazyLoad(node, resolve) { setTimeout(() => { self.getAreaForLazyLoad(node, resolve); }, 100); }, }, }; }, created() { if (this.isCurrentOrgDefaultArea) { // 通過當前賬號所在區划回顯 this.getCurrentOrg(); } if (this.isPortDefaultArea) { // 通過指定區划回顯 this.getDefaultArea(); } }, methods: { visibleChange(val) { console.log(val); if (val) { this.disabled = true; } else if (!val && this.addressName) { this.disabled = false; } }, belongRegionChange(val) { let res = this.$refs.areaSelect.getCheckedNodes(); console.log(res); if (res && res.length > 0) { this.addressName = res[0].pathLabels[0] + (res[0].pathLabels[1] || "") + (res[0].pathLabels[2] || "") + (res[0].pathLabels[3] || "") + (res[0].pathLabels[4] || ""); let areaNameObject = { provinceName: res[0].pathLabels[0], cityName: res[0].pathLabels[1], countyName: res[0].pathLabels[2], streetName: res[0].pathLabels[3], communityName: res[0].pathLabels[4], }; let areaCodeObject = { provinceCode: res[0].path[0], cityCode: res[0].path[1], countyCode: res[0].path[2], streetCode: res[0].path[3], communityCode: res[0].path[4], }; let data = { areaNameObject, areaCodeObject, }; this.$emit("selectedAreaList", data); } else { this.addressName = ""; let areaNameObject = { provinceName: "", cityName: "", countyName: "", streetName: "", communityName: "", }; let areaCodeObject = { provinceCode: "", cityCode: "", countyCode: "", streetCode: "", communityCode: "", }; let data = { areaNameObject, areaCodeObject, }; this.$emit("selectedAreaList", data); this.disabled = true; } }, getAreaForLazyLoad(node, resolve) { const { level } = node; let data = {}; if (level == 0) { data = { areaCode: "000000", }; } else if ( level == 1 || level == 2 || level == 3 || level == 4 || level == 5 ) { data = { areaCode: node.value, }; } else { return false; }
// 這里是接口 get("/area/getNextAreaInfoByCode", data) .then((res) => { if (res.succeed) { let isContain = data.areaCode.search(this.currentLastLevelCode); let oData = []; // let oData = this.formatAreaData(res.data, level); if (this.isCurrentOrgDefaultArea || this.isPortDefaultArea) { let arrList = this.formatAreaData(res.data, level); arrList.map((item, index) => { if ( (item.level <= this.CurrentLevel && this.isCurrentOrgDefaultArea) || (data.areaCode !== this.currentLastLevelCode && this.CurrentLevel >= level) || isContain != 0 ) { oData.push(Object.assign({}, item, { disabled: true })); } else { oData.push(Object.assign({}, item, { disabled: false })); } }); } else { oData = this.formatAreaData(res.data, level); } // this.belongRegoinOptions = oData if (oData.length == 0) { // // console.log('子節點數據為空', node) // node.syncCheckState(node.value); // const checkedNode = this.$refs.areaSelect.getCheckedNodes(); // // console.log('獲得剛才選中的節點', checkedNode) // node.syncCheckState(node.value) // node.doCheck(true) // this.$set(node, 'leaf', true) // oData = undefined; // resolve(oData); // return; } resolve(oData); } }) .catch((err) => { console.log(err); this.$message.error(err); }); }, formatAreaData(data, level) { return data.map((item) => { item.names = item.name; item.value = item.id; item.label = item.name; item.leaf = level >= (this.setLevel - 1); return item; }); }, handleAreaCode() { let areaCodeList = []; if (this.defaultHosuse.province) { areaCodeList.push(this.defaultHosuse.province); this.currentLastLevelCode = this.defaultHosuse.province; } if (this.defaultHosuse.city) { areaCodeList.push(this.defaultHosuse.city); this.currentLastLevelCode = this.defaultHosuse.city; } if (this.defaultHosuse.area) { areaCodeList.push(this.defaultHosuse.area); this.currentLastLevelCode = this.defaultHosuse.area; } if (this.defaultHosuse.town) { areaCodeList.push(this.defaultHosuse.town); this.currentLastLevelCode = this.defaultHosuse.town; } if (this.defaultHosuse.vill) { areaCodeList.push(this.defaultHosuse.vill); this.currentLastLevelCode = this.defaultHosuse.vill; } this.areaCodeList = areaCodeList; console.log(areaCodeList); if (this.addressName == "") { this.disabled = true; } else { this.disabled = false; } }, getDefaultArea() { console.log(this.defaultAddressInfos); this.addressName = this.defaultAddressInfos.addressName; this.defaultHosuse.province = this.defaultAddressInfos.provinceCode || ""; this.defaultHosuse.city = this.defaultAddressInfos.cityCode || ""; this.defaultHosuse.area = this.defaultAddressInfos.countyCode || ""; this.defaultHosuse.town = this.defaultAddressInfos.streetCode || ""; this.defaultHosuse.vill = this.defaultAddressInfos.communityCode || ""; this.CurrentLevel = this.defaultAddressInfos.level; this.handleAreaCode(); }, getCurrentOrg() { get("/organization/getCurrentOrg", {}).then((res) => { if (res.succeed) { let data = res.data; this.addressName = (data.provinceName || "") + (data.cityName || "") + (data.countyName || "") + (data.streetName || "") + (data.communityName || ""); // this.currentOrgLevel = data.level; // this.CurrentOrg = data; // let {province='provinceCode',city='cityCode',area='countyCode',town='streetCode',vill='communityCode'} = data // this.defaultHosuse = {province='provinceCode',city='cityCode',area='countyCode',town='streetCode',vill='communityCode'} this.defaultHosuse.province = data.provinceCode; this.defaultHosuse.city = data.cityCode; this.defaultHosuse.area = data.countyCode; this.defaultHosuse.town = data.streetCode; this.defaultHosuse.vill = data.communityCode; this.CurrentLevel = data.level; this.handleAreaCode(); let areaNameObject = { provinceName: data.provinceName, cityName: data.cityName, countyName: data.countyName, streetName: data.streetName, communityName: data.communityName, }; let areaCodeObject = { provinceCode: data.provinceCode, cityCode: data.cityCode, countyCode: data.countyCode, streetCode: data.streetCode, communityCode: data.communityCode, }; let val = { areaNameObject, areaCodeObject, }; this.$emit("selectedAreaList", val); } }); }, }, }; </script> <style scoped> </style>
使用文件:index.vue
<template> <div> <el-form ref="tableData" :rules="rules" :model="tableData" label-width="130px" size="mini" > <el-row> <el-col :span="12"> <el-form-item label="現常住地址:"> <Area-cascader @selectedAreaList="selectedAreaList" :isCurrentOrgDefaultArea="false" :clearable="true" ></Area-cascader> </el-form-item> </el-col> </el-row> </el-form> </div> </template> <script> import { get, downloadFile, post } from "@/apis/apicommon"; import AreaCascader from "@/components/common/areaCascader.vue"; export default { name: "page1", components: { AreaCascader, }, props: { }, data() { return { formData: {}, }; }, created() { }, mounted() {}, methods: { // 地址選中值 selectedAreaList(val) { // 這里是返回的區划name和code,一共有五級 console.log(val); let { provinceCode, cityCode, countyCode, streetCode, communityCode } = val.areaCodeObject; this.formData.province = provinceCode; this.formData.city = cityCode; this.formData.county = countyCode; this.formData.street = streetCode; this.formData.community = communityCode; let { provinceName, cityName, countyName, streetName, communityName } = val.areaNameObject; this.formData.provinceName = provinceName; this.formData.cityName = cityName; this.formData.countyName = countyName; this.formData.streetName = streetName; this.formData.communityName = communityName; }, }, }; </script> <style scoped> </style>
多看一下封裝的組件里面各種配置項,尤其是區划的數據格式,這里的code和name一起封裝,如果有任何疑問歡迎留言!