本文采用了vue3、element-plus、koa的作为demo的演示
以市辖区作为内容演示树形选择的懒加载及回显
0. 用平展的json模拟数据库表的结构region.json
[
{
"id": "440000000",
"name": "广东省",
"parentId": ""
},
{
"id": "440100000",
"name": "广州市",
"parentId": "440000000"
},
{
"id": "440106000",
"name": "天河区",
"parentId": "440100000"
},
{
"id": "440111000",
"name": "白云区",
"parentId": "440100000"
},
{
"id": "440300000",
"name": "深圳市",
"parentId": "440000000"
},
{
"id": "440305000",
"parentId": "440300000",
"name": "南山区"
},
{
"id": "440306000",
"parentId": "440300000",
"name": "宝安区"
}
]
1. 首先创建一个<el-tree-select>的组件
<template>
<el-tree-select
:model-value="modelValue"
node-key="id"
lazy
:expand-on-click-node="false"
:load="loadLazyRegion"
:props="{ label: 'name', value: 'id', children: 'children'}"
:cache-data="regionData"
@node-click="data => modelValue = data.id"
></el-tree-select>
</template>
<script setup>
import {ref, onMounted} from 'vue'
const modelValue = ref('')
const regionData = ref([])
async function loadLazyRegion(node, resolve) {
}
</script>
2. 创建懒加载子节点的逻辑(以koa接口为例)
router.get('/lazyRegion', async (ctx, next) => {
ctx.response.set('Access-Control-Allow-Origin', '*')
ctx.body = getLazyRegion(ctx.request.query.id || '')
})
// 通过id筛选出该节点下所有的直接子节点
function getLazyRegion(id) {
const region = require('./region.json')
const result = region.filter(e => e.parentId === id)
return result
}
3. 完善vue组件的懒加载逻辑
async function loadLazyRegion(node, resolve) {
const tree = (await axios.get('//localhost:3001/lazyRegion' + `?id=${node.data.id || ''}`)).data
resolve(tree)
console.log(`tree`, tree)
}
首先有了懒加载的效果:
如果不做回显逻辑,就会显示option的label:
4.增加懒树的回显逻辑(以koa接口为例)
router.get('/regionTree', async (ctx, next) => {
ctx.response.set('Access-Control-Allow-Origin', '*')
ctx.body = getRegionTree(ctx.request.query.id || '')
})
// 通过id生成该节点到根节点的树
function getRegionTree(id) {
const region = require('./region.json')
// 先根据id找到这个节点
let node = region.find(e => e.id === id)
if (!node) return [] // 没找到就返回空
// 定义parent和nodes平展数组
let parent
const nodes = [node]
// 生成nodes数组
do {
parent = region.find(e => e.id === node.parentId)
if (parent) {
// parent放在前面
nodes.unshift(parent)
}
// 滑动当前节点
node = parent
} while(parent)
// 通过nodes生成一颗tree
const tree = nodes[0]
let currentNode = tree
for (const item of nodes.slice(1)) {
currentNode.children ||= []
currentNode.children = [item]
// 滑动当前节点
currentNode = item
}
return [tree]
}
5. 完善vue组件的懒树回显逻辑
async function loadRegionTree(id) {
const tree = (await axios.get('//localhost:3001/regionTree' + `?id=${id || ''}`)).data
regionData.value = tree
}
onMounted(() => {
if (modelValue.value) {
loadRegionTree(modelValue.value)
}
})
回显效果如下:
总结
- 懒加载用的方式是根据一个节点的id,去找到该节点下的所有节点,是一个平展的一维数组
- 懒树回显用的方式是根据一个回显节点的id,去找到该节点到根节点的路径,形成一棵树
所有代码归纳
后端
router.get('/lazyRegion', async (ctx, next) => {
ctx.response.set('Access-Control-Allow-Origin', '*')
ctx.body = getLazyRegion(ctx.request.query.id || '')
})
// 通过id筛选出该节点下所有的直接子节点
function getLazyRegion(id) {
const region = require('./region.json')
const result = region.filter(e => e.parentId === id)
return result
}
router.get('/regionTree', async (ctx, next) => {
ctx.response.set('Access-Control-Allow-Origin', '*')
ctx.body = getRegionTree(ctx.request.query.id || '')
})
// 通过id生成该节点到根节点的树
function getRegionTree(id) {
const region = require('./region.json')
// 先根据id找到这个节点
let node = region.find(e => e.id === id)
if (!node) return [] // 没找到就返回空
// 定义parent和nodes平展数组
let parent
const nodes = [node]
// 生成nodes数组
do {
parent = region.find(e => e.id === node.parentId)
if (parent) {
// parent放在前面
nodes.unshift(parent)
}
// 滑动当前节点
node = parent
} while(parent)
// 通过nodes生成一颗tree
const tree = nodes[0]
let currentNode = tree
for (const item of nodes.slice(1)) {
currentNode.children ||= []
currentNode.children = [item]
// 滑动当前节点
currentNode = item
}
return [tree]
}
前端
<template>
<el-tree-select
:model-value="modelValue"
node-key="id"
lazy
:expand-on-click-node="false"
:load="loadLazyRegion"
:props="{ label: 'name', value: 'id', children: 'children'}"
:cache-data="regionData"
@node-click="data => modelValue = data.id"
></el-tree-select>
</template>
<script setup>
import {ref, onMounted} from 'vue'
import axios from 'axios'
const modelValue = ref('')
// const modelValue = ref('440106000')
const regionData = ref([])
async function loadLazyRegion(node, resolve) {
const tree = (await axios.get('//localhost:3001/lazyRegion' + `?id=${node.data.id || ''}`)).data
resolve(tree)
console.log(`tree`, tree)
}
async function loadRegionTree(id) {
const tree = (await axios.get('//localhost:3001/regionTree' + `?id=${id || ''}`)).data
regionData.value = tree
}
onMounted(() => {
if (modelValue.value) {
loadRegionTree(modelValue.value)
}
})
</script>