一、需求:
1.省市區級聯選擇,可多選
2.可以一鍵選擇某個區域下的所有數據
3.點擊省展開市,點擊市展開區,以此類推(可返回上一層或多層)
4.只獲取選擇的人
效果視頻
二、注意事項以及源碼
1.需要安裝uView UI組件庫,安裝地址uView UI官網
2.源碼,復制即用
<template><view class="container"><!-- 層級導航 --><view class="breadcrumb"><text class="breadcrumb-item" v-for="(item, index) in breadcrumbList" :key="index" @click="goBackToLevel(index)":class="{ 'breadcrumb-item-active': index === breadcrumbList.length - 1 }">{{ item }}<text v-if="index !== breadcrumbList.length - 1" class="breadcrumb-separator"> ></text></text></view><!-- 層級內容 --><view class="level-content"><view class="level-item" v-for="(item, index) in currentLevelData" :key="item.id"><!-- 將點擊事件移到內部元素,避免與復選框沖突 --><view class="level-item-left" @click="handleLevelItemClick(item)"><view class="level-icon" :style="{ backgroundColor: getLevelColor(item) }"><text class="level-icon-text">{{ getLevelCode(item) }}</text></view><view class="level-info"><text class="level-title">{{ item.name }}</text><text class="level-desc">{{ item.leaf ? item.emergencyPersonnel.phone : `${getAllLeafCount(item)} 個人員` }}</text></view></view><view class="select-checkbox"><u-checkbox :checked="isNodeSelected(item)" :indeterminate="isNodeIndeterminate(item)"@change="(value) => handleNodeSelect(item, value)" shape="circle" active-color="#4F46E5"></u-checkbox></view></view></view><!-- 底部操作欄 --><view class="footer-bar"><view class="selected-info"><u-icon name="account-fill" size="30" color="#4F46E5"></u-icon><text class="selected-count">已選擇 {{ selectedPersons.length }} 人</text></view><u-button type="primary" @click="toFormPage" :disabled="selectedPersons.length === 0"class="next-button">下一步</u-button></view></view>
</template><script>
export default {data() {return {// 人員數據結構(修改后:新增省份、簡化字段、常見姓名)personnelData: [{"id": "510000","name": "四川省","children": [{"id": "511400","name": "眉山市","children": [{"id": "市管理員","name": "市管理員","children": [{"id": "10","name": "趙六","children": [],"emergencyPersonnel": {"unitName": "市管理員","unitAddress": "眉山市政務服務中心","personName": "趙六","phone": "19162984018","provinceName": "四川省","cityName": "眉山市","countyName": ""},"leaf": true},{"id": "11","name": "孫七","children": [],"emergencyPersonnel": {"unitName": "市管理員","unitAddress": "眉山市政務服務中心","personName": "孫七","phone": "18180809001","provinceName": "四川省","cityName": "眉山市","countyName": ""},"leaf": true}],"emergencyPersonnel": null,"leaf": false}],"emergencyPersonnel": null,"leaf": false}],"emergencyPersonnel": null,"leaf": false},{"id": "440000","name": "廣東省","children": [{"id": "440100","name": "廣州市","children": [{"id": "天河區管理員","name": "天河區管理員","children": [{"id": "12","name": "周八","children": [],"emergencyPersonnel": {"unitName": "天河區管理員","unitAddress": "廣州市天河區政務中心","personName": "周八","phone": "18228880309","provinceName": "廣東省","cityName": "廣州市","countyName": "天河區"},"leaf": true},{"id": "13","name": "吳九","children": [],"emergencyPersonnel": {"unitName": "天河區管理員","unitAddress": "廣州市天河區政務中心","personName": "吳九","phone": "18990370720","provinceName": "廣東省","cityName": "廣州市","countyName": "天河區"},"leaf": true}],"emergencyPersonnel": null,"leaf": false},{"id": "海珠區管理員","name": "海珠區管理員","children": [{"id": "14","name": "鄭十","children": [],"emergencyPersonnel": {"unitName": "海珠區管理員","unitAddress": "廣州市海珠區政務中心","personName": "鄭十","phone": "15508337779","provinceName": "廣東省","cityName": "廣州市","countyName": "海珠區"},"leaf": true}],"emergencyPersonnel": null,"leaf": false}],"emergencyPersonnel": null,"leaf": false},{"id": "440300","name": "深圳市","children": [{"id": "南山區管理員","name": "南山區管理員","children": [{"id": "15","name": "錢十一","children": [],"emergencyPersonnel": {"unitName": "南山區管理員","unitAddress": "深圳市南山區政務中心","personName": "錢十一","phone": "15983336111","provinceName": "廣東省","cityName": "深圳市","countyName": "南山區"},"leaf": true}],"emergencyPersonnel": null,"leaf": false}],"emergencyPersonnel": null,"leaf": false}],"emergencyPersonnel": null,"leaf": false},{"id": "330000","name": "浙江省","children": [{"id": "330100","name": "杭州市","children": [{"id": "西湖區管理員","name": "西湖區管理員","children": [{"id": "16","name": "馮十二","children": [],"emergencyPersonnel": {"unitName": "西湖區管理員","unitAddress": "杭州市西湖區政務中心","personName": "馮十二","phone": "18783398823","provinceName": "浙江省","cityName": "杭州市","countyName": "西湖區"},"leaf": true},{"id": "17","name": "陳十三","children": [],"emergencyPersonnel": {"unitName": "西湖區管理員","unitAddress": "杭州市西湖區政務中心","personName": "陳十三","phone": "13547674447","provinceName": "浙江省","cityName": "杭州市","countyName": "西湖區"},"leaf": true}],"emergencyPersonnel": null,"leaf": false},{"id": "余杭區管理員","name": "余杭區管理員","children": [{"id": "18","name": "褚十四","children": [],"emergencyPersonnel": {"unitName": "余杭區管理員","unitAddress": "杭州市余杭區政務中心","personName": "褚十四","phone": "18160172259","provinceName": "浙江省","cityName": "杭州市","countyName": "余杭區"},"leaf": true}],"emergencyPersonnel": null,"leaf": false}],"emergencyPersonnel": null,"leaf": false}],"emergencyPersonnel": null,"leaf": false}],// 當前層級數據currentLevelData: [],// 層級導航路徑breadcrumbList: [],// 已選擇的人員selectedPersons: [],// 層級歷史記錄,用于返回levelHistory: []};},onLoad() {// 初始化層級數據(因personnelData改為數組,此處調整為加載所有省份)this.currentLevelData = this.personnelData;this.breadcrumbList = ["全國"];this.levelHistory = [this.currentLevelData];},methods: {// 獲取層級顏色getLevelColor(item) {if (item.leaf) {return '#E0E7FF';}const colors = ['#E0F2FE', '#DBEAFE', '#EFF6FF', '#F0FDF4', '#FEF3C7'];let hash = 0;for (let i = 0; i < item.name.length; i++) {hash = item.name.charCodeAt(i) + ((hash << 5) - hash);}return colors[Math.abs(hash) % colors.length];},// 獲取層級代碼getLevelCode(item) {if (item.leaf) {return item.name.charAt(0);}return item.name.substring(0, 2);},// 遞歸獲取某個節點下的所有葉子節點getAllLeafNodes(node) {let leafNodes = [];if (node.leaf) {leafNodes.push(node);} else if (node.children && node.children.length > 0) {node.children.forEach(child => {leafNodes = leafNodes.concat(this.getAllLeafNodes(child));});}return leafNodes;},// 計算某個節點下的葉子節點總數getAllLeafCount(node) {return this.getAllLeafNodes(node).length;},// 判斷某個節點的選中狀態isNodeSelected(node) {const leafNodes = this.getAllLeafNodes(node);if (node.leaf) {return this.selectedPersons.some(p => p.id === node.id);}return leafNodes.every(leaf =>this.selectedPersons.some(p => p.id === leaf.id));},// 判斷某個非葉子節點是否半選isNodeIndeterminate(node) {if (node.leaf) return false;const leafNodes = this.getAllLeafNodes(node);const selectedLeafCount = leafNodes.filter(leaf =>this.selectedPersons.some(p => p.id === leaf.id)).length;return selectedLeafCount > 0 && selectedLeafCount < leafNodes.length;},// 將葉子節點轉換為selectedPersons格式convertLeafToSelected(leafNode) {return {id: leafNode.id,name: leafNode.name,phone: leafNode.emergencyPersonnel.phone,unitName: leafNode.emergencyPersonnel.unitName,unitAddress: leafNode.emergencyPersonnel.unitAddress,provinceName: leafNode.emergencyPersonnel.provinceName,cityName: leafNode.emergencyPersonnel.cityName,countyName: leafNode.emergencyPersonnel.countyName};},// 處理節點選擇 - 修正事件參數問題handleNodeSelect(node, checked) {const leafNodes = this.getAllLeafNodes(node);if (checked) {// 選中操作:添加所有未選中的葉子節點leafNodes.forEach(leaf => {const isExist = this.selectedPersons.some(p => p.id === leaf.id);if (!isExist) {this.selectedPersons.push(this.convertLeafToSelected(leaf));}});} else {// 取消選中:移除所有相關葉子節點this.selectedPersons = this.selectedPersons.filter(p =>!leafNodes.some(leaf => leaf.id === p.id));}},// 處理層級項點擊handleLevelItemClick(item) {if (!item.leaf && item.children && item.children.length > 0) {// 判斷當前層級是否是最外層(全國層級)const isRootLevel = this.breadcrumbList.length === 1 && this.breadcrumbList[0] === "全國";if (!isRootLevel) {this.breadcrumbList.push(item.name);} else {// 從全國進入省份時,更新導航路徑this.breadcrumbList = ["全國", item.name];}this.currentLevelData = item.children;this.levelHistory.push(this.currentLevelData);}},// 返回上一級goBackToLevel(index) {if (index >= this.breadcrumbList.length - 1) return;// 調整導航路徑this.breadcrumbList = this.breadcrumbList.slice(0, index + 1);// 調整層級歷史this.levelHistory = this.levelHistory.slice(0, index + 1);// 更新當前層級數據this.currentLevelData = this.levelHistory[index];},// 前往表單頁面toFormPage() {console.log(this.selectedPersons);if (this.selectedPersons.length === 0) {this.$u.toast('請至少選擇一個人員');return;}}}
};
</script><style scoped>
/* 樣式保持不變 */
.container {background-color: #F8F8F8;min-height: 100vh;padding-bottom: 60px;
}.breadcrumb {padding: 12px 15px;background-color: white;display: flex;align-items: center;font-size: 14px;overflow-x: auto;white-space: nowrap;
}.breadcrumb-item {color: #6B7280;padding: 0 2px;
}.breadcrumb-item-active {color: #4F46E5;font-weight: 500;
}.breadcrumb-separator {margin: 0 4px;color: #D1D5DB;
}.level-content {background-color: white;padding-top: 10px;
}.level-item {display: flex;align-items: center;justify-content: space-between;padding: 12px 15px;border-bottom: 1px solid #F3F4F6;
}.level-item-left {display: flex;align-items: center;width: 80%;
}.level-icon {width: 36px;height: 36px;border-radius: 50%;display: flex;align-items: center;justify-content: center;
}.level-icon-text {font-size: 14px;font-weight: 500;color: #4F46E5;
}.level-info {margin-left: 12px;
}.level-title {font-size: 16px;color: #1F2937;
}.level-desc {font-size: 12px;color: #6B7280;margin-top: 2px;display: block;
}.select-checkbox {width: 20px;height: 20px;display: flex;align-items: center;justify-content: center;
}.footer-bar {position: fixed;bottom: 0;left: 0;right: 0;background-color: white;display: flex;align-items: center;justify-content: space-between;padding: 10px 15px;border-top: 1px solid #F3F4F6;}.selected-info {display: flex;align-items: center;color: #1F2937;font-size: 14px;
}.selected-count {margin-left: 5px;
}.next-button {width: 120px;border-radius: 20px;
}
</style>