element plus 的Tree 懒加载。省市县镇村树形懒加载 电脑版发表于:2025/3/12 10:45 <img src="https://img.tnblog.net/arcimg/aojiancc2/f49e3421c09d435f8f43e257f9d0d5b5.png" style="width:299px;height:auto;"> tn2> 这里的示例代码是做的县镇村tree懒加载联动数据。接口数据这些换成自己的就行。有根据countyId查询区县下面镇的数据,有根据镇id查询镇下面村的数据等待接口。受限这些原始的表结构,县镇村是三种不同的表,这个接口根据自己的实际情况出来就行。 [TOC] ### 基础的代码如下 ``` <template> <div class="app-container"> <el-card> <el-tree :data="treeData" :props="defaultProps" lazy :load="loadNode" node-key="id" @node-click="handleNodeClick" /> </el-card> </div> </template> <script setup lang="ts" name="tasks"> import { defineAsyncComponent, reactive, onMounted, toRefs, ref } from 'vue'; import request from '/@/utils/requestTools'; const state = reactive({ title: '更新', schoolID: null, schoolList: [ { id: 1, name: '小', }, { id: 2, name: '大', }, ], }); // 定义树形数据的结构 interface TreeNode { id: number; label: string; children?: TreeNode[]; isLeaf?: boolean; // 用于标识是否为叶子节点(村数据) countyId?: string; // 区县ID,用于乡镇数据的加载 townId?: string; // 乡镇ID,用于村数据的加载 villageId?: string; // 村ID,用于组数据的加载 } // 初始化树形数据,只包含区县节点 const treeData = ref<TreeNode[]>([]); // 定义Tree组件的props const defaultProps = ref<any>({ children: 'children', label: 'label', isLeaf: 'isLeaf', // 自定义属性,用于标识叶子节点 }); // 加载节点数据的方法 const loadNode = async (node: any, resolve: any) => { if (node.level === 0) { // 根节点,加载所有区县数据 try { // const response = await axios.get('/api/api1'); // const data = response.data.data; const result: any = await request.get('/watertap/api/County/getAllCountyByCityId',{ choiseCity: '530600000000'}); const data = result.data; const counties = data.map((county:any) => ({ id: county.id, label: county.name, countyId: county.countyId, isLeaf: false, // 区县节点不是叶子节点 })); resolve(counties); } catch (error) { console.error('加载区县数据失败:', error); resolve([]); } } else if (node.level === 1 && node.data.countyId) { // 区县节点,加载对应的乡镇数据 try { // const response = await axios.get(`/api/api2`, { // params: { countyId: node.data.countyId }, // }); // const data = response.data.data; const result: any = await request.get('/watertap/api/town/getTownByCountyId', { countyId: node.data.countyId }); const data = result.data; const towns = data.map((town:any) => ({ id: town.id, label: town.name, townId: town.townId, isLeaf: false, // 乡镇节点不是叶子节点 })); resolve(towns); } catch (error) { console.error('加载乡镇数据失败:', error); resolve([]); } } else if (node.level === 2 && node.data.townId) { // 乡镇节点,加载对应的村数据 try { // const response = await axios.get('/api/api3', { // params: { townId: node.data.townId.replace('townId:', '') }, // 假设townId字段需要处理以匹配API要求 // }); const result: any = await request.get('/watertap/api/village/GetVillageByTownId', { townId:node.data.townId }); // 注意:这里isLeaf应为true const data = result.data; const villages = data.map((village:any) => ({ id: village.id, // 假设村数据中有id字段 label: village.name, // 假设村数据中有name字段 villageId:village.villageId, isLeaf: true, // 村节点是叶子节点 })); resolve(villages); } catch (error) { console.error('加载村数据失败:', error); resolve([]); } } else { resolve([]); } }; // 处理节点点击事件 const handleNodeClick = (data: TreeNode) => { console.log('点击的节点:', data); }; onMounted(() => {}); </script> <style scoped="scoped" lang="scss"> .app-container { padding: 15px; } </style> ``` ### 配合左右结构,左边树形,右边表格等,树形tree 动态自适应屏幕高度(就是多一点样式) 代码如下: ``` <template> <div class="app-container"> <el-card> <el-tree :data="treeData" :props="defaultProps" lazy :load="loadNode" node-key="id" @node-click="handleNodeClick" /> </el-card> </div> </template> <script setup lang="ts" name="tasks"> import { defineAsyncComponent, reactive, onMounted, toRefs, ref } from 'vue'; import request from '/@/utils/requestTools'; const state = reactive({ title: '更新', schoolID: null, schoolList: [ { id: 1, name: '小', }, { id: 2, name: '大', }, ], }); // 定义树形数据的结构 interface TreeNode { id: number; label: string; children?: TreeNode[]; isLeaf?: boolean; // 用于标识是否为叶子节点(村数据) countyId?: string; // 区县ID,用于乡镇数据的加载 townId?: string; // 乡镇ID,用于村数据的加载 villageId?: string; // 村ID,用于组数据的加载 } // 初始化树形数据,只包含区县节点 const treeData = ref<TreeNode[]>([]); // 定义Tree组件的props const defaultProps = ref<any>({ children: 'children', label: 'label', isLeaf: 'isLeaf', // 自定义属性,用于标识叶子节点 }); // 加载节点数据的方法 const loadNode = async (node: any, resolve: any) => { if (node.level === 0) { // 根节点,加载所有区县数据 try { // const response = await axios.get('/api/api1'); // const data = response.data.data; const result: any = await request.get('/watertap/api/County/getAllCountyByCityId',{ choiseCity: '530600000000'}); const data = result.data; const counties = data.map((county:any) => ({ id: county.id, label: county.name, countyId: county.countyId, isLeaf: false, // 区县节点不是叶子节点 })); resolve(counties); } catch (error) { console.error('加载区县数据失败:', error); resolve([]); } } else if (node.level === 1 && node.data.countyId) { // 区县节点,加载对应的乡镇数据 try { // const response = await axios.get(`/api/api2`, { // params: { countyId: node.data.countyId }, // }); // const data = response.data.data; const result: any = await request.get('/watertap/api/town/getTownByCountyId', { countyId: node.data.countyId }); const data = result.data; const towns = data.map((town:any) => ({ id: town.id, label: town.name, townId: town.townId, isLeaf: false, // 乡镇节点不是叶子节点 })); resolve(towns); } catch (error) { console.error('加载乡镇数据失败:', error); resolve([]); } } else if (node.level === 2 && node.data.townId) { // 乡镇节点,加载对应的村数据 try { // const response = await axios.get('/api/api3', { // params: { townId: node.data.townId.replace('townId:', '') }, // 假设townId字段需要处理以匹配API要求 // }); const result: any = await request.get('/watertap/api/village/GetVillageByTownId', { townId:node.data.townId }); // 注意:这里isLeaf应为true const data = result.data; const villages = data.map((village:any) => ({ id: village.id, // 假设村数据中有id字段 label: village.name, // 假设村数据中有name字段 villageId:village.villageId, isLeaf: true, // 村节点是叶子节点 })); resolve(villages); } catch (error) { console.error('加载村数据失败:', error); resolve([]); } } else { resolve([]); } }; // 处理节点点击事件 const handleNodeClick = (data: TreeNode) => { console.log('点击的节点:', data); }; onMounted(() => {}); </script> <style scoped="scoped" lang="scss"> .app-container { padding: 15px; } </style> ```