百度小程序省市区三级联动终极版
之前的那篇百度小程序三级联动的博客自认为写得不够好,比较偏理论,基本在讲picker组件中的各个参数的意思;这篇是在上一篇的基础上对三级联动重写了一遍,实现的效果要比上一篇好,还支持用户点击编辑收获地址的时候input框内显示省市区地址。
上篇的三级联动的省市区数据都是通过发送请求获取的,本篇的三级联动的数据都是使用本地文件里面的数据,具体看下面代码。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// 导入验证js const app = getApp(); import WxValidate from "../../utils/WxValidate"; import { axios } from "../../utils/request"; import region from "../../utils/region"; import { setAddressList, getAddressList, setProvinceList, getProvinceList } from "../../utils/storage"; import { showToast } from "../../utils/index"; Page({ data: { multiIndex: [0, 0, 0], // 默认的下标 [省、市、区] step: 0, // 默认显示请选择 // 设置默认收货地址按钮选中状态 value: "" }, onLoad() { // console.log("openid: ", app.globalData.openid); // 初始化表单验证规则 this.initValidate(); // 获取省的数据 this.getProvince(); }, // 提交表单 formSubmit(e) { if (this.data.step == 0) { swan.showToast({ title: "请选择收货城市", icon: "none", duration: 4000, mask: false }); return; } let params = e.detail.value; // console.log(params); // 省的名字 let DeliveryName = this.data.provinceList[params["receivingAddress"][0]] .name; // 市的名字 let CityName = this.data.cityList[params["receivingAddress"][1]].name; // 区的名字 let storeName = this.data.storeList[params["receivingAddress"][2]].name; // 如果市和区名称相同就只市的名称 let DeliveryAddress; (CityName == storeName) ? DeliveryAddress = DeliveryName + CityName : DeliveryAddress = DeliveryName + CityName + storeName; // console.log("DeliveryAddress是不是undefined", DeliveryAddress + params.CustomArea); // console.log("DeliveryAddress是不是undefined", DeliveryAddress + params.CustomArea); let storeNumber = params["receivingAddress"][2]; let storeCode = this.data.storeList[storeNumber].code; if (!this.WxValidate.checkForm(params)) { //表单元素验证不通过,此处给出相应提示 let error = this.WxValidate.errorList[0]; this.showToast(error); return false; } else { // 构建请求数据结构 let addressObj = { openid: app.globalData.openid, Name: params.Name, phone: params.phone, IsDefault: this.data.value, // 详细地址 CustomArea: params.CustomArea, // 省市区+详细地址 DeliveryAddress: DeliveryAddress + params.CustomArea, RegionCode: storeCode }; // console.log("跳啊: ", addressObj); axios({ url: "/api/Account/AddAddress", method: "POST", data: addressObj }, true) .then(res => { if (res.data.IsSuccess) { // 发送请求获取服务器数据库中最新的收货地址列表数据 // app.getAddressList(); // 直接存储新的数据 setAddressList(res.data.ResultObject); // 跳转到我的收获地址页面 swan.navigateBack({ // url: "/pages/address/address", delta: 1, success: res => { // 添加成功 showToast("添加收货地址成功"); }, fail: () => { // console.log("跳转失败,请重试!"); } }); let shopcar = res.data.ResultObject for (let i = 0, len = shopcar.length; i < len; i++) { if (shopcar[i].IsDefaultDelivery) { let currentMyress = { name: shopcar[i].DeliveryConsignee, //地址名字 phone: shopcar[i].ConsigneePhone2, //地址电话 deliveryAddress: shopcar[i].DeliveryAddress, //地址 deliveryId: shopcar[i].DeliveryId, //地址id IsDefaultDelivery: shopcar[i].IsDefaultDelivery//是否默认地址 } swan.setStorageSync('currentMyress', currentMyress); } } } else { // 添加失败 showToast(res.data.Msg); } }) .catch(error => { // console.log(error); }); } }, // checkedbox状态改变 checkboxChange(e) { const { value } = e.detail; // value是一个数组,如果length不等于0说明选中了 value.length != 0 ? this.setData({ value: "true" }) : this.setData({ value: "false" }); }, /* 表单验证函数 */ initValidate() { let rules = { Name: { required: true, maxlength: 10 }, phone: { required: true, tel: true }, CustomArea: { required: true }, receivingAddress: { required: true } /* receivingAddressValue: { required: true } */ }; let message = { Name: { required: "请输入姓名", rangelength: "请输入2~4个汉字" }, phone: { required: "请输入11位手机号码", tel: "请输入正确的手机号码" }, CustomArea: { required: "请输入详细地址" }, receivingAddress: { required: "请选择收货地区" }, receivingAddressValue: { required: "必须选择收货地区" } }; //实例化当前的验证规则和提示消息 this.WxValidate = new WxValidate(rules, message); }, // 错误消息提示框 showToast(error) { swan.showToast({ title: error.msg, icon: "none", duration: 2000, mask: false }); }, // 获取省的数据 getProvince() { // 从本地的省市区文件中获取省数据 let data = region.province; data.splice(31, 4); let provinceList = [...data]; // 将返回的数据放在一个数组里面,现在的数据结构是一个数组对象 let provinceArr = data.map(item => { return item.name; }); this.setData({ multiArray: [provinceArr, [], []], // 更新三维数组 provinceList, // 省原始数据 provinceArr // 省级所有名称 }); let defaultCode = this.data.provinceList[0].code; this.setData({ currentProviceKey: defaultCode // 保存当前省级的key(也就是code) }); this.getCity(defaultCode); // 通过省级的code获取当前省级下面的市级数据 }, getCity(code) { // 获取市级的数据 this.setData({ currentProviceKey: code // 保存当前选择的市级code }); // 先找到接收的code对应的市级数据 let data = region.city.filter(item => { if (item.parentId == code) { return true; } }); let cityList = [...data[0].list]; let cityArr = [...data[0].list].map(item => { return item.name; }) this.setData({ multiArray: [this.data.provinceArr, cityArr, []], // 更新三维数组 cityList, // 保存下市级所有数据 cityArr }); // console.log(this.data.multiArray); let defaultCode = this.data.cityList[0].code; // 用第一个code获取区数据 this.setData({ currentCityKey: defaultCode // 存下当前选择的城市的key }); this.getStore(defaultCode); }, getStore(code) { this.setData({ // 获取区级数据 currentCityKey: code // 更新当前选择的市级Key }); let data = region.area.filter(item => { if (item.parentId == code) { return true; } }); // console.log("store Data: ", data); let storeList = [...data[0].list]; let storeArr = [...data[0].list].map(item => { return item.name; }) // console.log("区数据 >", storeArr); this.setData({ multiArray: [this.data.provinceArr, this.data.cityArr, storeArr], // 重新赋值三级数组 storeList, // 保存区级原始数据 storeArr }); }, columnchange(e) { // 滚动选择器触发的事件 let column = e.detail.column; // column表示改变了第几列(下标从0开始) let value = e.detail.value; // value的值表示变更值得下标 let multiIndex = JSON.parse(JSON.stringify(this.data.multiIndex)); multiIndex[column] = e.detail.value; // 第几列改变了就是对应multiIndex的第几个,更新他 switch ( column // 处理不同的逻辑 ) { case 0: // 第一列更改 就是省级的更改 let currentProviceKey = this.data.provinceList[e.detail.value].code; // 重新赋值省级编号 if (currentProviceKey != this.data.currentProviceKey) { // 判断当前key是不是正真的更新 this.getCity(currentProviceKey); // 获取当前key下面的市级数据 } multiIndex[1] = 0; // 将市默认选择第1个 this.setData(multiIndex); // 更新数据 break; case 1: // 市发生变化 let currentCityKey = this.data.cityList[e.detail.value].code; // let currentCityParentCode = this.data.cityList[e.detail.value].ParentCode; if (currentCityKey != this.data.currentCityKey) { this.getStore(currentCityKey); // 获取区 } multiIndex[2] = 0; // 区默认选择第一个 this.setData(multiIndex); // 更新数据 break; } }, pickchange(e) { // console.log("value改变了...", e.detail.value); this.setData({ step: 1, // 更新用于是否默认显示地区的状态值 multiIndex: e.detail.value }); } });
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
const app = getApp(); // 导入验证js import WxValidate from "../../utils/WxValidate"; import { axios } from "../../utils/request"; import { getUserInfo, setUserInfo, setAddressList, getAddressList } from "../../utils/storage"; import region from "../../utils/region"; Page({ data: { multiArray: [], // 三维数组数据 multiIndex: [0, 0, 0], // 默认的下标 [省、市、区] step: 0, // 默认显示请选择 // 设置默认收货地址按钮选中状态 value: "", DeliveryId: "", detailAddressInfo: {} }, onLoad(params) { // 获取传递过来的数据并赋值 const { DeliveryId } = params; this.setData({ DeliveryId }); this.getDetailAddressInfo(); // 初始化表单验证规则 this.initValidate(); // 获取省的数据 }, // 提交表单 formSubmit(e) { /* if(this.data.step == 0){ swan.showToast({ title: '请选择收货城市', icon: "none", duration: 4000, mask: false }); return; } */ let params = e.detail.value; // 省的名字 let DeliveryName = this.data.provinceList[params["receivingAddress"][0]].name; // 市的名字 let CityName = this.data.cityList[params["receivingAddress"][1]].name; // 区的名字 let storeName = this.data.storeList[params["receivingAddress"][2]].name; let DeliveryAddress; (CityName == storeName) ? DeliveryAddress = DeliveryName + CityName : DeliveryAddress = DeliveryName + CityName + storeName; let storeNumber = params["receivingAddress"][2]; let storeCode = this.data.storeList[storeNumber].code; let DeliveryId = this.data.DeliveryId; if (!this.WxValidate.checkForm(params)) { //表单元素验证不通过,此处给出相应提示 let error = this.WxValidate.errorList[0]; this.showToast(error); return false; } else { // 构建请求数据结构 let addressObj = { openid: app.globalData.openid, Name: params.Name, phone: params.phone, IsDefault: this.data.value, // 详细地址 CustomArea: params.CustomArea, // 省市区+详细地址 DeliveryAddress: DeliveryAddress + params.CustomArea, RegionCode: storeCode, DeliveryId }; axios({ url: "/api/Account/UpdateDelivery", method: "POST", data: addressObj }) .then(res => { if (res.data.IsSuccess) { // 获取数据库最新数据 app.getAddressList(); // 跳转到我的收获地址页面 swan.navigateBack({ url: "/pages/address/address", delta: 1, success: res => { // 添加成功 swan.showToast({ title: "修改收货地址成功", icon: "none", duration: 2000, mask: false }); }, fail: () => { // console.log("跳转失败,请重试!"); } }); } else { // 添加失败 this.showToast(res.data.Msg); } }) .catch(error => { // console.log(error); }); } }, // checkedbox状态改变 checkboxChange(e) { const { value } = e.detail; // value是一个数组,如果length不等于0说明选中了 value.length != 0 ? this.setData({ value: "true" }) : this.setData({ value: "false" }); }, /* 表单验证函数 */ initValidate() { let rules = { Name: { required: true, maxlength: 10 }, phone: { required: true, tel: true }, CustomArea: { required: true }, receivingAddress: { required: true } }; let message = { Name: { required: "请输入姓名", rangelength: "请输入2~4个汉字个汉字" }, phone: { required: "请输入11位手机号码", tel: "请输入正确的手机号码" }, CustomArea: { required: "请输入详细地址" }, receivingAddress: { required: "请选择收货地区" } }; //实例化当前的验证规则和提示消息 this.WxValidate = new WxValidate(rules, message); }, // 错误消息提示框 showToast(error) { swan.showToast({ title: error.msg, icon: "none", duration: 4000, mask: false }); }, // 获取省的数据 getProvince() { let data = region.province; data.splice(31, 4); let provinceList = [...data]; // 将返回的数据放在一个数组里面,现在的数据结构是一个数组对象 let provinceArr = data.map(item => item.name); // 获取数据里面的value值,只用数据的名称 this.setData({ multiArray: [provinceArr, [], []], // 更新三维数组 provinceList, // 省原始数据 provinceArr // 省级所有名称 }); let defaultCode = this.data.provinceList[this.data.multiIndex[0]].code; // 使用第一项当做参数获取市级数据 this.setData({ currentProviceKey: defaultCode // 保存当前省级的key(也就是AreaCode) }); this.getCity(defaultCode); // 通过省级的AreaCode获取当前省级下面的市级数据 }, getCity(code) { // 获取市级的数据 this.setData({ currentProviceKey: code // 保存当前选择的市级code }); let data = region.city.filter(item => { if (item.parentId == code) { return true; } }); let cityList = [...data[0].list]; let cityArr = [...data[0].list].map(item => { return item.name; }); this.setData({ multiArray: [this.data.provinceArr, cityArr, []], // 更新三维数组 cityArr, // 保存下市级所有名称 cityList // 保存下市级所有数据 }); let defaultCode = this.data.cityList[this.data.multiIndex[1]].code; // 用第一个code获取区数据 this.setData({ currentCityKey: defaultCode // 存下当前选择的城市的key }); // 通过市级的AreaCode获取当前市级下面的区级数据 this.getStore(defaultCode); }, getStore(code) { // 获取区级数据 this.setData({ currentCityKey: code // 更新当前选择的市级Key }); // 处理直辖市和特殊的区,获取区的时候使用市的code 如果不是直辖市就通过市级的AreaCode获取当前市级下面的区级数据 let data = region.area.filter(item => { if (item.parentId == code) { return true; } }); let storeList = [...data[0].list]; let storeArr = [...data[0].list].map(item => { return item.name; }); this.setData({ multiArray: [this.data.provinceArr, this.data.cityArr, storeArr], // 重新赋值三级数组 storeList, // 保存区级原始数据 storeArr // 保存区级名称 }); }, columnchange(e) { // 滚动选择器触发的事件 let column = e.detail.column; // column表示改变了第几列(下标从0开始) let value = e.detail.value; // value的值表示变更值得下标 let multiIndex = JSON.parse(JSON.stringify(this.data.multiIndex)); multiIndex[column] = e.detail.value; // 第几列改变了就是对应multiIndex的第几个,更新他 switch ( column // 处理不同的逻辑 ) { case 0: // 第一列更改 就是省级的更改 let currentProviceKey = this.data.provinceList[e.detail.value].code; // 重新赋值省级编号 if (currentProviceKey != this.data.currentProviceKey) { // 判断当前key是不是正真的更新 this.getCity(currentProviceKey); // 获取当前key下面的市级数据 } multiIndex[1] = 0; // 将市默认选择第1个 this.setData({ multiIndex }); // 更新数据 break; case 1: // 市发生变化 let currentCityKey = this.data.cityList[e.detail.value].code; if (currentCityKey != this.data.currentCityKey) { this.getStore(currentCityKey); // 获取区 } multiIndex[2] = 0; // 区默认选择第一个 this.setData({ multiIndex }); // 更新数据 break; } }, pickchange(e) { this.setData({ step: 1, // 更新用于是否默认显示地区的状态值 multiIndex: e.detail.value }); }, // 根据DeliveryId发请求获取收货地址详细信息 getDetailAddressInfo() { const DeliveryId = this.data.DeliveryId; // 减少HTTP请求,降低渲染时间 if (!this.data.detailAddressInfo.DeliveryId) { axios({ url: "/api/Account/GetDeliveryById", method: "POST", data: { openid: app.globalData.openid, deliveryId: DeliveryId } }) .then(res => { if (res.data.IsSuccess) { let detailAddressInfo = res.data.ResultObject; this.setData({ detailAddressInfo }); this.getDetailAddressInfoMethod(); } else { swan.showToast({ title: res.data.Msg, icon: "none", duration: 3000, mask: false }); } }) .catch(error => { // console.log(error); }); }else { this.getDetailAddressInfoMethod(); } }, getDetailAddressInfoMethod() { let RegionCode = this.data.detailAddressInfo.RegionCode; // // 通过截取RegionCode查找省市级 let code = RegionCode.slice(0, 2) + "0000"; let provinceIndex = region.province.findIndex(item => item.code == code); // // 获取市的数据 let cityCode = RegionCode.slice(0, 4) + "00"; let cityName = region.city.filter(item => { return item.list.find(item2 => { return item2.code == cityCode; }); }); let cityIndex = cityName[0].list.findIndex(item => item.code == cityCode); // // 获取区的数据 let storeCode = RegionCode; let storeName = region.area.filter(item => { return item.list.find(item2 => { return item2.code == storeCode; }); }); let storeIndex = storeName[0].list.findIndex( item => item.code == storeCode ); this.setData( { multiIndex: [provinceIndex, cityIndex, storeIndex] }, () => { this.getProvince(); } ); // 备份 // let RegionCode = this.data.detailAddressInfo.RegionCode; // // 通过截取RegionCode查找省市级 // let code = RegionCode.slice(0,2) + '0000'; // let provinceName = region.province.filter(item=>{ // return item.code == code; // }); // provinceName = provinceName[0].name // // 获取市的数据 // let cityCode = RegionCode.slice(0,4) + '00'; // let cityName = region.city.filter(item=>{ // return item.list.find(item2=>{ // return item2.code == cityCode; // }); // }) // cityName = cityName[0].list.filter(item=>{ // return item.code == cityCode; // }) // cityName = cityName[0].name; // // 获取区的数据 // let storeCode = RegionCode; // let storeName = region.area.filter(item=>{ // return item.list.find(item2=>{ // return item2.code == storeCode; // }); // }) // storeName = storeName[0].list.filter(item=>{ // return item.code == storeCode; // }) // storeName = storeName[0].name; // this.setData({ // multiArray: [[provinceName], [cityName], [storeName]] // }) }, pickClick(e) { this.getProvince(); }, pickCancel(e) { this.getDetailAddressInfo(); } });
编辑收获地址时获取当前地址的省市区的操作步骤是:
1.发请求拿到当前地址的信息,里面会包含一个regionCode,就是区的编号
2.通过对区的编号进行字符串截取得到市和省的编号,然后做把市很省的编号在文件里面做匹配,通过findIndex()函数找到当前对象所在数组中的下表
3.在初始函数 getDetailAddressInfoMethod中将上面三个编号所在数组对象中的index拿出来setData更新到multiIndex中即可