写在前面
未采用: 前端放置js 或者 json文件进行 省市区三级联动
采用: 前端组件 + 后端接口实现三级联动
原因:首先微信小程序有大小限制,能省则省,其次:方便后台维护省市区数据,完整省市区每年更新好像还是挺频繁的
方案
后端保存数据格式
例如
前端要展示 “福建省-厦门市-集美区“ 直接根据 - 分割截取就行
12,1,3 :代表选择数据 对应项中的第几个
9261586716360729,9261586716360744:代表选择省跟市的id
这两个数组串 主要是回显数据用 ,如下,点击展开回显
前端实现代码 [有注释说明]
template
<uni-popup ref="cityDialog" type="bottom"><view class="uni-list"><view class="uni-list-cell"><view class="uni-list-cell-left">当前选择</view><view class="uni-list-cell-db"><picker @columnchange="columnchange" @change="changeAddress" range-key="name" :value="value":range="addressList" mode="multiSelector"><view class="uni-input">{{cityValue}}</view></picker></view></view></view></uni-popup>
data
export default {data() { return { //存放三级联动数据addressList: [[],[],[]],//选择的省回显idprovince: "",//选择的市回显idcity: "",//回显值value: [],//前端展示数据cityValue:'',timer:null}}
}
create
created() {console.log("created...")this.userInfo = uni.getStorageSync("userInfo");const info = this.userInfo.cityif (info) {//info 就是上面方案里说的数据库city字段值 // 福建省-厦门市-集美区-12,1,3-9261586716360729,9261586716360744//前端展示数据this.cityValue = info.split('-').slice(0, 3).join('-');//数据库 省市表主键 idconst idPart = info.split('-')[4].split(',');this.province = idPart[0]this.city = idPart[1] this.value = []// 添加回显id this.value.push(...info.split('-')[3].split(',').map(Number)); }//初始化省数据this.initProvince(); },
methods
columnchange(e) {clearTimeout(this.timer)const _this = thisthis.timer = setTimeout(() => {const {column,value} = e.detailconst item = {..._this.addressList[column][value]}if (column === 0) {this.province = item.id//清楚选择二级数据,不然切换别的省,第三级永远是上一次选择this.city = ''_this.loadCity(item.id)} else if (column === 1) {this.city = item.id_this.loadThird(item.id)}}, 500)},initProvince() {//调用接口获取省数据listProvince().then(res => {if (res.code == 200) {this.addressList.splice(0, 1, [...res.data])//如果this.province 数据没有,表示数据库没有记录if (!this.province) {this.province = res.data[0].id}this.loadCity(this.province)}})},loadCity(parentId) {listCity(parentId).then(res => {if (res.code == 200) {this.addressList.splice(1, 1, [...res.data])if(!this.city) {this.city = res.data[0].id}this.loadThird(this.city)}})},loadThird(parentId) {listCity(parentId).then(res => {if (res.code == 200) {this.addressList.splice(2, 1, [...res.data])}})},changeAddress(e) {console.log("e", e)const _this = this_this.value = []_this.value.push(...e.detail.value)const arr = e.detail.valuelet str = ''arr.forEach((el, index) => {const {name} = _this.addressList[index][el]str += `${index ? '-':''}${name}`})this.cityValue = str// 最终数据 省-市-区-选择数据第几个(逗号隔开)- 选择数据id(逗号隔开) //例:福建省-厦门市-集美区-12,1,3-9261586716360729,9261586716360744str = str + "-" + e.detail.value + "-" + this.province + "," + this.city//TODO 保存,或者修改 数据 this.editInfo.city = str},
后端实现代码
后端就两个接口 简单接口
/*** 获取省份* @return province*/@GetMapping("listProvince")public AjaxResult listProvince () {return AjaxResult.success(sysProvinceCityDistrictService.listProvince());}```bash/*** 获取市/区县* @return province*/@GetMapping("listCity")public AjaxResult listCity (@RequestParam("parentId") String parentId) {return AjaxResult.success(sysProvinceCityDistrictService.listCity(parentId));}
service接口文件这边就忽略了,直接impl逻辑
逻辑也很简单,查缓存 ,没有就数据库,有就缓存
Constants.NUMBER_ZERO 常量 0
@Override
public List<CityVo> listProvince() {if (Boolean.TRUE.equals(redisTemplate.hasKey(CacheConstants.CITY_CACHE_KEY))) {//从缓存获取return (List<CityVo>) redisTemplate.opsForValue().get(CacheConstants.CITY_CACHE_KEY);}List<CityVo> cityVos = sysProvinceCityDistrictMapper.listProvince();if (CollectionUtils.isEmpty(cityVos)) {return null;}redisTemplate.opsForValue().set(CacheConstants.CITY_CACHE_KEY, cityVos);return cityVos;}@Overridepublic List<CityVo> listCity(String parentId) {List<CityVo> list = new ArrayList<>();List<SysProvinceCityDistrict> reultList;if (Boolean.TRUE.equals(redisTemplate.hasKey(CacheConstants.CITY_CACHE_KEY_CITY))) {//从缓存获取reultList = (List<SysProvinceCityDistrict>) redisTemplate.opsForValue().get(CacheConstants.CITY_CACHE_KEY_CITY);} else {QueryWrapper<SysProvinceCityDistrict> query = new QueryWrapper<>();query.ne("parent_id", Constants.NUMBER_ZERO);reultList = sysProvinceCityDistrictMapper.selectList(query);}if (CollectionUtils.isEmpty(reultList)) {return list;}reultList.stream().filter(s -> s.getParentId().equals(parentId)).forEach(info -> {CityVo cityVo = new CityVo();cityVo.setId(info.getId());cityVo.setName(info.getName());list.add(cityVo);});redisTemplate.opsForValue().set(CacheConstants.CITY_CACHE_KEY_CITY, reultList);return list;}
CityVo
/*** @author rongpeng.xia* @date 2024-08-13 10:33:59*/
@Data
public class CityVo implements Serializable {private static final long serialVersionUID = 1L;private String id;private String name;
}
(SysProvinceCityDistrict)表实体类
/*** (SysProvinceCityDistrict)表实体类** @author xiarp* @since 2024-08-12 15:58:13*/
@SuppressWarnings("serial")
@Data
public class SysProvinceCityDistrict implements Serializable {private static final long serialVersionUID = 286422671100375146L;/*** id*/private String id;/*** 名字*/private String name;/*** 父id*/private String parentId;/*** 编码*/private String code;/*** 父编码*/private String parentCode;/*** 创建者*/private Long createId;/*** 创建时间*/private Date createTime;/*** 修改者*/private Long updateId;/*** 修改时间*/private Date updateTime;
}
前端参考的连接:https://blog.csdn.net/m0_73205643/article/details/140954162