注:公司领导要求封装一个区划选择器,最大支持五级区划,并且适用的场景有很多:数据全部由接口所得并且是懒加载形式;能够回显当前登录账号所属级别的默认地址;还能够回显接口返回的默认地址;能够配置区划选择器的最大级别;禁止当前级别之前的地址被选择等等功能,花了两天的事时间,终于算是完善优化好了,供大家一起参考,代码若有缺陷还望指针,感谢!以下是源代码:
特别说明:这里面使用懒加载形式调取接口,每次接口返回一个级别的数据,如第一次默认返回所有省级,点击安徽省,传安徽省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一起封装,如果有任何疑问欢迎留言!
