注:公司領導要求封裝一個區划選擇器,最大支持五級區划,並且適用的場景有很多:數據全部由接口所得並且是懶加載形式;能夠回顯當前登錄賬號所屬級別的默認地址;還能夠回顯接口返回的默認地址;能夠配置區划選擇器的最大級別;禁止當前級別之前的地址被選擇等等功能,花了兩天的事時間,終於算是完善優化好了,供大家一起參考,代碼若有缺陷還望指針,感謝!以下是源代碼:
特別說明:這里面使用懶加載形式調取接口,每次接口返回一個級別的數據,如第一次默認返回所有省級,點擊安徽省,傳安徽省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一起封裝,如果有任何疑問歡迎留言!
