一、需求:
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>