开发笔记:uniapp+vue+微信小程序 picker +后端 省市区三级联动

写在前面

未采用: 前端放置js 或者 json文件进行 省市区三级联动
采用: 前端组件 + 后端接口实现三级联动
原因:首先微信小程序有大小限制,能省则省,其次:方便后台维护省市区数据,完整省市区每年更新好像还是挺频繁的

方案

后端保存数据格式

例如

前端要展示 "福建省-厦门市-集美区" 直接根据 - 分割截取就行

12,1,3 :代表选择数据 对应项中的第几个
9261586716360729,9261586716360744:代表选择省跟市的id

这两个数组串 主要是回显数据用 ,如下,点击展开回显

前端实现代码 [有注释说明]

template
bash 复制代码
	<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
bash 复制代码
export default {
   data() { 
     return { 
       //存放三级联动数据
       addressList: [[],[],[]],
       //选择的省回显id
       province: "",
       //选择的市回显id
	   city: "",
	   //回显值
	   value: [],
	   //前端展示数据
	   cityValue:'',
	   timer:null
     }
   }
}
create
bash 复制代码
	created() {
			console.log("created...")
			this.userInfo = uni.getStorageSync("userInfo");
			const info = this.userInfo.city
			if (info) {
			//info 就是上面方案里说的数据库city字段值  
			// 福建省-厦门市-集美区-12,1,3-9261586716360729,9261586716360744
			//前端展示数据
			this.cityValue = info.split('-').slice(0, 3).join('-');
			//数据库 省市表主键 id
			const 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
bash 复制代码
columnchange(e) {
				clearTimeout(this.timer)
				const _this = this
				this.timer = setTimeout(() => {
					const {
						column,
						value
					} = e.detail
					const 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.value
				let str = ''
				arr.forEach((el, index) => {
					const {
						name
					} = _this.addressList[index][el]

					str += `${index ? '-':''}${name}`
				})
				this.cityValue = str
				// 最终数据 省-市-区-选择数据第几个(逗号隔开)- 选择数据id(逗号隔开) 
				//例:福建省-厦门市-集美区-12,1,3-9261586716360729,9261586716360744
				str = str + "-" + e.detail.value + "-" + this.province + "," + this.city
				//TODO 保存,或者修改 数据 
				this.editInfo.city = str
			},

后端实现代码

后端就两个接口 简单接口
bash 复制代码
 /**
     *  获取省份
     * @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

bash 复制代码
@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;
    }

    @Override
    public 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

bash 复制代码
/**
 * @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)表实体类

bash 复制代码
/**
 * (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

相关推荐
阿伟来咯~3 分钟前
一些 uniapp相关bug
uni-app·bug
Yawesh_best29 分钟前
思源笔记轻松连接本地Ollama大语言模型,开启AI写作新体验!
笔记·语言模型·ai写作
嚣张农民1 小时前
推荐3个实用的760°全景框架
前端·vue.js·程序员
落魄小二2 小时前
el-table 表格索引不展示问题
javascript·vue.js·elementui
CXDNW2 小时前
【网络面试篇】HTTP(2)(笔记)——http、https、http1.1、http2.0
网络·笔记·http·面试·https·http2.0
使者大牙2 小时前
【大语言模型学习笔记】第一篇:LLM大规模语言模型介绍
笔记·学习·语言模型
neter.asia2 小时前
vue中如何关闭eslint检测?
前端·javascript·vue.js
ssf-yasuo2 小时前
SPIRE: Semantic Prompt-Driven Image Restoration 论文阅读笔记
论文阅读·笔记·prompt
十一吖i2 小时前
前端将后端返回的文件下载到本地
vue.js·elementplus
光影少年2 小时前
vue2与vue3的全局通信插件,如何实现自定义的插件
前端·javascript·vue.js