小程序省市級聯組件使用

背景。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
英文地址,請注明出處:http://en.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;在進行…