小程序省市级联组件使用

背景。uni-data-picker组件用起来不方便。调整后级联效果欠佳,会关闭弹窗需要重新选择。

  • 解决方案。让cursor使用uniapp 原生组件生成懒加载省市级联
<template><view class="picker-cascader"><view class="cascader-label"><text v-if="required" class="required-mark">*</text><text class="label-text">{{ label }}</text></view><pickermode="multiSelector":range="range":value="defaultValue":disabled="disabled || readonly"@change="handleChange"@cancel="handleCancel"@columnchange="handleColumnChange"@confirm="handleConfirm"><view class="picker-input" :data-disabled="disabled || readonly"><text v-if="displayText" class="picker-text">{{ displayText }}</text><text v-else class="picker-placeholder">{{ placeholder }}</text><text class="picker-arrow">></text></view></picker></view>
</template><script>
import { getProvinceList, getCityListByProvince, getCountyListByCity } from '@/api/regionApi.js';
import { getProvinceListMock, getCityListByProvinceMock, getCountyListByCityMock } from '@/mock/regionMock.js';export default {name: 'PickerCascader',props: {/*** 标签文本*/label: {type: String,default: '所在地区'},/*** 绑定的值,支持字符串格式 "provinceCode,cityCode,countyCode" 或对象格式 {provinceCode: "110000", cityCode: "110100", countyCode: "110101"}*/regionStr: {type: [String, Object],default: ''},/*** 占位符文本*/placeholder: {type: String,default: '请选择省市区'},/*** 是否禁用*/disabled: {type: Boolean,default: false},/*** 是否只读*/readonly: {type: Boolean,default: false},/*** 最大选择级数,支持2-3级*/maxLevel: {type: Number,default: 3,validator: function (value) {return value >= 2 && value <= 3;}},/*** 是否必填*/required: {type: Boolean,default: false}},data() {return {// picker的range数据,格式为二维数组range: [],// picker的value数据,格式为数组,表示每列选中的索引defaultValue: [0, 0, 0],// 省份数据provinces: [],// 城市数据缓存,格式为 {provinceCode: cities}cityCache: {},// 县级数据缓存,格式为 {cityCode: counties}countyCache: {},// 当前选中的编码selectedCodes: ['', '', ''],// 当前选中的文本selectedTexts: ['', '', ''],// 是否正在加载数据loading: false};},computed: {/*** 显示文本*/displayText() {const texts = this.selectedTexts.filter((text) => text);return texts.length > 0 ? texts.join(' ') : '';}},watch: {/*** 监听value 变化,更新选中值*/regionStr: {handler(newVal) {console.log('value变化', newVal);this.initFromValue(newVal);},immediate: true}},mounted() {this.initData();},methods: {/*** 初始化数据*/async initData() {try {this.loading = true;console.log('PickerCascader 开始初始化数据...');await this.loadProvinces();this.initRange();this.initFromValue(this.regionStr);console.log('PickerCascader 数据初始化完成');console.log('省份数据:', this.provinces.length, '个');console.log('range数据:', this.range);} catch (error) {console.error('初始化数据失败:', error);} finally {this.loading = false;}},/*** 加载省份数据*/async loadProvinces() {try {console.log('开始加载省份数据...');const res = await getProvinceList();if (res.code === 200 && Array.isArray(res.data)) {this.provinces = res.data;console.log('从API获取省份数据成功:', this.provinces.length, '个省份');} else {// 使用mock数据console.log('API返回异常,使用mock数据');const mockRes = getProvinceListMock();this.provinces = mockRes.data;}console.log('省份数据加载完成:', this.provinces.length, '个省份');} catch (error) {console.error('获取省份列表失败:', error);// 使用mock数据const mockRes = getProvinceListMock();this.provinces = mockRes.data;console.log('使用mock数据,省份数量:', this.provinces.length);}},/*** 初始化range数据*/initRange() {// 初始化省份列const provinceColumn =this.provinces && this.provinces.length > 0? this.provinces.map((province) => ({text: province.name,code: province.code})): [];// 初始化城市列(空数据,等待选择省份后加载)const cityColumn = [];// 初始化县级列(空数据,等待选择城市后加载)const countyColumn = [];this.range = [provinceColumn, cityColumn, countyColumn];},/*** 从value初始化选中值*/initFromValue(value) {if (!value) {this.resetSelection();return;}let provinceCode = '';let cityCode = '';let countyCode = '';if (typeof value === 'string') {const codes = value.split(',');provinceCode = codes[0] || '';cityCode = codes[1] || '';countyCode = codes[2] || '';} else if (typeof value === 'object') {provinceCode = value.provinceCode || '';cityCode = value.cityCode || '';countyCode = value.countyCode || '';}this.setSelectionByCodes(provinceCode, cityCode, countyCode);},/*** 根据编码设置选中值*/async setSelectionByCodes(provinceCode, cityCode, countyCode) {if (!provinceCode) {this.resetSelection();return;}// 查找省份索引const provinceIndex = this.provinces.findIndex((p) => p.code === provinceCode);if (provinceIndex === -1) {this.resetSelection();return;}// 设置省份选中this.value[0] = provinceIndex;this.selectedCodes[0] = provinceCode;this.selectedTexts[0] = this.provinces[provinceIndex].name;// 加载城市数据await this.loadCities(provinceCode, provinceIndex);if (cityCode && this.range[1] && this.range[1].length > 0) {// 查找城市索引const cities = this.range[1];const cityIndex = cities.findIndex((c) => c.code === cityCode);if (cityIndex !== -1) {this.value[1] = cityIndex;this.selectedCodes[1] = cityCode;this.selectedTexts[1] = cities[cityIndex].text;// 如果是三级联动,加载县级数据if (this.maxLevel === 3) {await this.loadCounties(cityCode, provinceIndex, cityIndex);if (countyCode && this.range[2] && this.range[2].length > 0) {// 查找县级索引const counties = this.range[2];const countyIndex = counties.findIndex((c) => c.code === countyCode);if (countyIndex !== -1) {this.value[2] = countyIndex;this.selectedCodes[2] = countyCode;this.selectedTexts[2] = counties[countyIndex].text;}}}}}// 强制更新this.$forceUpdate();},/*** 重置选中值*/resetSelection() {this.value = [0, 0, 0];this.selectedCodes = ['', '', ''];this.selectedTexts = ['', '', ''];},/*** 加载城市数据*/async loadCities(provinceCode, provinceIndex) {console.log('开始加载城市数据,省份编码:', provinceCode);// 检查缓存if (this.cityCache[provinceCode]) {console.log('使用缓存的城市数据:', this.cityCache[provinceCode].length, '个城市');this.range[1] = this.cityCache[provinceCode];return;}try {const res = await getCityListByProvince(provinceCode);let cities = [];if (res.code === 200 && Array.isArray(res.data)) {cities = res.data;console.log('从API获取城市数据成功:', cities.length, '个城市');} else {// 使用mock数据console.log('API返回异常,使用mock数据');const mockRes = getCityListByProvinceMock(provinceCode);cities = mockRes.data;}// 转换为picker所需格式const cityColumn =cities && cities.length > 0? cities.map((city) => ({text: city.name,code: city.code})): [];console.log('城市数据转换完成:', cityColumn.length, '个城市');// 缓存数据this.cityCache[provinceCode] = cityColumn;this.range[1] = cityColumn;// 重置后续列的选中值this.value[1] = 0;this.value[2] = 0;this.selectedCodes[1] = '';this.selectedCodes[2] = '';this.selectedTexts[1] = '';this.selectedTexts[2] = '';// 清空县级数据this.range[2] = [];console.log('城市数据加载完成,range更新为:', this.range);// 强制更新this.$forceUpdate();} catch (error) {console.error('获取城市列表失败:', error);// 使用mock数据const mockRes = getCityListByProvinceMock(provinceCode);const cities = mockRes.data;const cityColumn =cities && cities.length > 0? cities.map((city) => ({text: city.name,code: city.code})): [];this.cityCache[provinceCode] = cityColumn;this.range[1] = cityColumn;console.log('使用mock数据,城市数量:', cityColumn.length);this.$forceUpdate();}},/*** 加载县级数据*/async loadCounties(cityCode, provinceIndex, cityIndex) {console.log('开始加载县级数据,城市编码:', cityCode);// 检查缓存if (this.countyCache[cityCode]) {console.log('使用缓存的县级数据:', this.countyCache[cityCode].length, '个县区');this.range[2] = this.countyCache[cityCode];return;}try {const res = await getCountyListByCity(cityCode);let counties = [];if (res.code === 200 && Array.isArray(res.data)) {counties = res.data;console.log('从API获取县级数据成功:', counties.length, '个县区');} else {// 使用mock数据console.log('API返回异常,使用mock数据');const mockRes = getCountyListByCityMock(cityCode);counties = mockRes.data;}// 转换为picker所需格式const countyColumn =counties && counties.length > 0? counties.map((county) => ({text: county.name,code: county.code})): [];console.log('县级数据转换完成:', countyColumn.length, '个县区');// 缓存数据this.countyCache[cityCode] = countyColumn;this.range[2] = countyColumn;// 重置县级选中值this.value[2] = 0;this.selectedCodes[2] = '';this.selectedTexts[2] = '';console.log('县级数据加载完成,range更新为:', this.range);// 强制更新this.$forceUpdate();} catch (error) {console.error('获取县级列表失败:', error);// 使用mock数据const mockRes = getCountyListByCityMock(cityCode);const counties = mockRes.data;const countyColumn =counties && counties.length > 0? counties.map((county) => ({text: county.name,code: county.code})): [];this.countyCache[cityCode] = countyColumn;this.range[2] = countyColumn;console.log('使用mock数据,县级数量:', countyColumn.length);this.$forceUpdate();}},/*** 处理列变化事件*/async handleColumnChange(e) {const { column, value } = e.detail;console.log('列变化事件:', { column, value, currentRange: this.range });// 更新选中索引this.value[column] = value;if (column === 0) {// 省份变化if (this.range[0] && this.range[0][value]) {const provinceCode = this.range[0][value].code;const provinceName = this.range[0][value].text;console.log('选择省份:', { provinceCode, provinceName });this.selectedCodes[0] = provinceCode;this.selectedTexts[0] = provinceName;// 加载城市数据await this.loadCities(provinceCode, value);}// 重置后续列的选中值this.value[1] = 0;this.value[2] = 0;this.selectedCodes[1] = '';this.selectedCodes[2] = '';this.selectedTexts[1] = '';this.selectedTexts[2] = '';// 清空县级数据this.range[2] = [];} else if (column === 1) {// 城市变化if (this.range[1] && this.range[1][value]) {const cityCode = this.range[1][value].code;const cityName = this.range[1][value].text;console.log('选择城市:', { cityCode, cityName });this.selectedCodes[1] = cityCode;this.selectedTexts[1] = cityName;// 如果是三级联动,加载县级数据if (this.maxLevel === 3) {await this.loadCounties(cityCode, this.value[0], value);}}// 重置县级选中值this.value[2] = 0;this.selectedCodes[2] = '';this.selectedTexts[2] = '';} else if (column === 2) {// 县级变化if (this.range[2] && this.range[2][value]) {const countyCode = this.range[2][value].code;const countyName = this.range[2][value].text;console.log('选择县级:', { countyCode, countyName });this.selectedCodes[2] = countyCode;this.selectedTexts[2] = countyName;}}// 强制更新this.$forceUpdate();},/*** 处理选择确认事件*/handleChange(e) {const { value } = e.detail;console.log('选择确认事件:', { value, range: this.range });// 更新选中索引this.value = value;// 更新选中编码和文本for (let i = 0; i < value.length; i++) {if (this.range[i] && this.range[i][value[i]] && value[i] >= 0) {this.selectedCodes[i] = this.range[i][value[i]].code;this.selectedTexts[i] = this.range[i][value[i]].text;}}// 触发change事件const result = this.formatResult();console.log('最终结果:', result);this.$emit('change', result);},/*** 处理确认事件*/handleConfirm(e) {console.log('确认事件:', e);// 这里可以添加额外的确认逻辑},/*** 处理取消事件*/handleCancel() {this.$emit('cancel');},/*** 格式化结果*/formatResult() {const codes = this.selectedCodes.filter((code) => code);const texts = this.selectedTexts.filter((text) => text);// 根据maxLevel返回相应格式if (this.maxLevel === 2) {return codes.slice(0, 2).join(',');} else {return codes.join(',');}}}
};
</script><style scoped>
.picker-cascader {background-color: #fff;border-radius: 12rpx;padding: 30rpx;margin-bottom: 20rpx;box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
}.cascader-label {display: flex;align-items: center;margin-bottom: 20rpx;
}.required-mark {color: #ff4757;font-size: 28rpx;margin-right: 8rpx;font-weight: bold;
}.label-text {font-size: 28rpx;color: #333;font-weight: 500;
}.picker-input {display: flex;align-items: center;justify-content: space-between;height: 88rpx;padding: 0 24rpx;border: 2rpx solid #e1e5e9;border-radius: 8rpx;background-color: #fff;transition: all 0.3s ease;
}.picker-input:active {border-color: #2979ff;box-shadow: 0 0 0 4rpx rgba(41, 121, 255, 0.1);
}.picker-text {font-size: 28rpx;color: #333;flex: 1;
}.picker-placeholder {font-size: 28rpx;color: #999;flex: 1;
}.picker-arrow {font-size: 24rpx;color: #999;transform: rotate(90deg);
}/* 禁用状态 */
.picker-input[data-disabled='true'] {background-color: #f8f9fa;color: #999;cursor: not-allowed;
}.picker-input[data-disabled='true'] .picker-text,
.picker-input[data-disabled='true'] .picker-placeholder {color: #999;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/92339.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/92339.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java技术栈/面试题合集(8)-Redis篇

场景 Java入门、进阶、强化、扩展、知识体系完善等知识点学习、性能优化、源码分析专栏分享: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/140870227 通过对面试题进行系统的复习可以对Java体系的知识点进行查漏补缺。 注: 博客: 霸道流氓气质-CSDN博…

川翔云电脑:引领开启算力无边界时代

一、何为云电脑&#xff1f;重新定义“主机”概念 云电脑将传统本地计算机的核心硬件资源&#xff08;CPU、GPU、内存、硬盘等&#xff09;集中部署于远程高性能数据中心&#xff0c;通过网络技术将虚拟桌面实时传输到您的任意访问设备上。 ​​如同将高配主机装入云端&#…

tc 介绍

目录 1.背景 2. tc介绍 3. tc 丢包 1.背景 需要使用tc 构造丢包场景&#xff0c;注意tc 丢包不能确定丢弃的是否是payload 数据包&#xff0c;有可能丢弃 ack 包。 2. tc介绍 1. 无法正常使用 [rootpool-100-1-1-18 /]# [rootpool-100-1-1-18 /]# tc qdisc add dev swif…

LabVIEW注册表操作

​本文围绕LabVIEW中操作Windows 注册表的 4 个 VI 展开&#xff0c;介绍其功能、使用场景等并对比&#xff0c;助力工程师高效运用注册表交互功能。各 VI 功能说明&#xff08;一&#xff09;Write the Key功能&#xff1a;创建新注册表键&#xff0c;设置其值&#xff0c;随后…

阿里云部署若依后,浏览器能正常访问,但是apifox和小程序访问后报错链接被重置

项目场景&#xff1a;阿里云部署若依后浏览器能正常通过https访问,但是在apifox和小程序调用接口的时候生报错E问题描述apifox报错&#xff1a;curl报错&#xff1a;通过curl可以清楚的看到通过域名是能准确的访问到IP地址的&#xff0c;说明这个DNS是没有问题的&#xff0c;但…

升级 Elasticsearch 到新的 AWS Java SDK

作者&#xff1a;来自 Elastic David Turner, Dianna Hohensee Elasticsearch 使用官方的 AWS Java SDK 集成了某些 Amazon Web Services (AWS) 功能。这些集成最早在近 10 年前发布的 Elasticsearch 2.0 版本中引入。 最近&#xff0c;AWS 宣布 Elasticsearch 过去十年使用的…

从0到1学习微服务项目黑马头条day01-《APP端登录功能实现》

个人主页&#xff1a;VON文章所属专栏&#xff1a;黑马头条个人唯一微信&#xff1a;微信 有一起学习微服务的小伙伴可以加作者微信&#xff1a;单击即可添加 目录 一、前言 二、项目概述 1、技术栈 2、项目引入 三、改造项目 1、创建heima-leadnews-user 2、创建实体…

Renesas Electronics RZ/V2N 评估套件

简介Renesas Electronics RZ/V2N评估套件采用RZ/V2N中档嵌入式AI微处理器 (MPU) 为嵌入式人工智能 (AI) 应用提供全面的开发平台。该评估套件包括两块板&#xff1a;主板 (RTK0EF0186C02000BJ)&#xff0c;紧凑的153mm x 100mm外形尺寸和RTK0EF0168B00000BJ扩展板。其核心是RZ/…

使用PHP与Apache实现服务器端文件管理

引言 作为前端开发者&#xff0c;你可能经常需要与服务器文件系统交互。本文将详细介绍如何通过PHP配合Apache实现服务器端文件管理功能。即使你没有任何PHP经验&#xff0c;也能按照本教程实现完整解决方案&#xff01; 系统准备 PHP下载与安装 访问PHP官网下载页面 选择与…

在Word和WPS文字中如何输入汉字的偏旁部首

如何在Word和WPS文字中输入偏旁部首&#xff1f;许多输入法会把常见的偏旁部首直接放到词库&#xff0c;对于词库中没有的可以试试这个方法&#xff1a;先输入一个有这个偏旁部首的字&#xff0c;尽量简单一点的&#xff0c;然后选中这个字插入-符号-其他符号。滚动到这个偏旁部…

day44 力扣1143.最长公共子序列 力扣1035.不相交的线 力扣53. 最大子序和 力扣392.判断子序列

最长公共子序列 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下删除某些字符&…

应用7:用小白量化智能体金融模块做一个股票选股工具

应用7&#xff1a;用小白量化智能体金融模块做一个股票选股工具 【小白量化智能体】包含有丰富的金融模块。可以让智能体写各种金融量化工具。 我用让小白量化智能体写一个股票选股工具。 我们给【小白量化智能体】一个程序生成话术。 帮我写一个 选股 的应用程序&#xff0c;要…

Qt Frameless Widget跨平台无边框窗口

Qt开发的窗口程序&#xff0c;它的标题栏样式是无法修改的&#xff0c;这个是系统来控制&#xff0c;程序可以调整标题&#xff0c;图标等&#xff0c;但是各个系统可能表现不一致&#xff0c;比如说标题&#xff0c;window10下在标题栏最左边&#xff0c;而UOS则在中间&#x…

使用 IntelliJ IDEA + Spring JdbcTemplate 操作 MySQL 指南

使用 IntelliJ IDEA Spring JdbcTemplate 操作 MySQL 完全指南 一、开发环境搭建&#xff08;基于 IDEA&#xff09; 1. 创建 Spring Boot 项目 打开 IDEA → New Project → Spring Initializr选择&#xff1a; Project SDK: Java 17依赖项&#xff1a;Spring Web, Spring…

从愤怒的小鸟来看Unity武器拖尾的特效优化

目录 前言 素材下载 介绍 官方文档 不添加拖尾的效果 添加拖尾 代码控制拖尾生成 拖尾排序问题 效果 修改拖尾高度和存活时间 效果 待机时无拖尾 效果 参考 前言 在游戏开发过程中&#xff0c;我们经常需要为武器添加拖尾特效&#xff0c;效果如下所示 Unity 自…

Web开发模式 前端渲染 后端渲染 身份认证

Web 开发模式 # 目前主流的Web 开发模式 两种 一、基于 服务器端渲染 的传统 Web开发模式 二、基于 前后端分离 的新型 Web开发模式# 服务端渲染的优缺点# 优点&#xff1a;1. 前端耗时少因为服务端负责动态生成 HTML内容&#xff0c;浏览器&#xff08;包括手…

C++ WonderTrader 源码分析之浮点数处理

介绍 在WonderTrader的文件decimal.h中封装了一些用于浮点数&#xff08;double&#xff09;处理的工具函数&#xff0c;主要目的是解决浮点数精度误差带来的比较问题&#xff0c;以及进行一些常用运算&#xff08;四舍五入、比较、取模等&#xff09;。下面我们逐行详细解释每…

指针——练习

sizeof和strlensizeofsizeof是用来计算变量所占内存空间大小的&#xff0c;单位是字节&#xff0c;如果操作数是类型&#xff0c;计算的是使用类型创建的变量所占内存空间的大小。sizeof只关注占用内存空间的大小&#xff0c;不在乎内存中存放什么数据。我们来看一下这个代码&a…

华为云 Flexus 部署 coze-studio

华为云 Flexus 部署 coze-studio 一、前置 主机和程序&#xff1a;云主机&#xff08;Flexus L ubuntu&#xff09; coze-studio 部署方式&#xff1a;docker&#xff08;提前装好的&#xff09; 字节跳动开源AI智能体开发平台Coze&#xff0c;具备极低的硬件门槛——2核CPU…

Linux系统编程Day7 -- 基于Linux系统知识的第一个程序

往期内容回顾 自动化构建工具-make/Makefile gcc/g编译及链接 Vim工具的使用 Linux常用工具&#xff08;yum与vim&#xff09; ​​​​​​ Linux系统编程Day4-- Shell与权限 编写第一个Linux程序 今天我们要利用我们所学到的Linux语言来编译第一个Linux程序&#xff0c;在进行…