目录
- 一、介绍
- 二、目标
- 三、代码
- 四、完成
一、介绍
我们的国家国土面积十分的广阔,目前中国有 34 个省级行政区,包括 23 个省、5 个自治区、4 个直辖市、2 个特别行政区。其下面还有几千个县级区域,以及更多的乡镇区域。
这样层层嵌套的省市区数据在实际开发中是如何处理的呢?下面请运用所学,解开这个谜团吧~
二、目标
在实际开发中,由于省市区等层级较多,使得数据结构按照嵌套关系来存储则过于复杂,一般在数据库中会将省市区数据解耦,每条信息以并列关系存储在一张表中,结构如下:
[
{
id: "51", // 区域 id
name: "四川省", // 区域名字
pid: "0", // 区域的父级区域 id
},
{
id: "5101",
name: "成都市",
pid: "51", // 成都的父级是四川省,所以 pid 是 51
},
// ...
];
各级行政区域通过 pid 关联起来。
但是这样平铺的数据放在前端页面展示的话,用户很难看出其中的层级关系,所以需要将平铺的结构转化为树状结构,便于前端展示:
[
{
id: "51", // 地址 id
name: "四川省", // 地址名
pid: "0", // 该地址的父节点 id
children: [
{
id: "5101",
name: "成都市",
pid: "51",
children: [
{
id: "510101",
name: "市辖区",
pid: "5101",
children: [], // 如果该区域节点没有子集,children 则为空数组!!!
},
// ...
],
},
// ...
],
},
// ...
];
补充文件 convert-to-tree.js 中的 convertToTree 工具函数,使其实现我们需要的功能:
- 接收平铺的区域信息数组,并将其转化为树状结构,最终数据结构如上面介绍中所示(树状结构,且对于没有子集的叶子节点,其 children 属性设置为空数组)。
- 并且还接收一个 rootId,用于标识返回哪一个区域下面的所有节点。默认为 0 表示返回所有省份信息(在我们的示例数据中,所有省份的 pid 都为 0)。
完成图:
三、代码
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>平铺数据生成树状结构</title>
</head>
<style>
#output-container {
width: 600px;
}
</style>
<body>
<div id="output-container"></div>
<script>
module = {};
</script>
<script type="text/javascript" src="./convert-to-tree.js"></script>
<script>
const convertToTreeFn = module.exports;
const output = document.getElementById("output-container");
const regions = [
{
id: "51",
name: "四川省",
pid: "0",
},
{
id: "5101",
name: "成都市",
pid: "51",
},
{
id: "5103",
name: "自贡市",
pid: "51",
},
{
id: "5104",
name: "攀枝花市",
pid: "51",
},
{
id: "5105",
name: "泸州市",
pid: "51",
},
{
id: "5107",
name: "绵阳市",
pid: "51",
},
{
id: "510101",
name: "市辖区",
pid: "5101",
},
{
id: "510104",
name: "锦江区",
pid: "5101",
},
{
id: "510105",
name: "青羊区",
pid: "5101",
},
{
id: "510106",
name: "金牛区",
pid: "5101",
},
{
id: "510107",
name: "武侯区",
pid: "5101",
},
{
id: "510108",
name: "成华区",
pid: "5101",
},
{
id: "510112",
name: "龙泉驿区",
pid: "5101",
},
{
id: "510113",
name: "青白江区",
pid: "5101",
},
{
id: "510114",
name: "新都区",
pid: "5101",
},
{
id: "510115",
name: "温江区",
pid: "5101",
},
{
id: "510116",
name: "双流区",
pid: "5101",
},
{
id: "510117",
name: "郫都区",
pid: "5101",
},
{
id: "510118",
name: "新津区",
pid: "5101",
},
{
id: "510121",
name: "金堂县",
pid: "5101",
},
{
id: "510129",
name: "大邑县",
pid: "5101",
},
{
id: "510131",
name: "蒲江县",
pid: "5101",
},
{
id: "510181",
name: "都江堰市",
pid: "5101",
},
{
id: "510182",
name: "彭州市",
pid: "5101",
},
{
id: "510183",
name: "邛崃市",
pid: "5101",
},
{
id: "510184",
name: "崇州市",
pid: "5101",
},
{
id: "510185",
name: "简阳市",
pid: "5101",
},
{
id: "510301",
name: "市辖区",
pid: "5103",
},
{
id: "510302",
name: "自流井区",
pid: "5103",
},
{
id: "510303",
name: "贡井区",
pid: "5103",
},
{
id: "510304",
name: "大安区",
pid: "5103",
},
{
id: "510311",
name: "沿滩区",
pid: "5103",
},
{
id: "510321",
name: "荣县",
pid: "5103",
},
{
id: "510322",
name: "富顺县",
pid: "5103",
},
{
id: "510401",
name: "市辖区",
pid: "5104",
},
{
id: "510402",
name: "东区",
pid: "5104",
},
{
id: "510403",
name: "西区",
pid: "5104",
},
{
id: "510411",
name: "仁和区",
pid: "5104",
},
{
id: "510421",
name: "米易县",
pid: "5104",
},
{
id: "510422",
name: "盐边县",
pid: "5104",
},
{
id: "510501",
name: "市辖区",
pid: "5105",
},
{
id: "510502",
name: "江阳区",
pid: "5105",
},
{
id: "510503",
name: "纳溪区",
pid: "5105",
},
{
id: "510504",
name: "龙马潭区",
pid: "5105",
},
{
id: "510521",
name: "泸县",
pid: "5105",
},
{
id: "510522",
name: "合江县",
pid: "5105",
},
{
id: "510524",
name: "叙永县",
pid: "5105",
},
{
id: "510525",
name: "古蔺县",
pid: "5105",
},
{
id: "510701",
name: "市辖区",
pid: "5107",
},
{
id: "510703",
name: "涪城区",
pid: "5107",
},
{
id: "510704",
name: "游仙区",
pid: "5107",
},
{
id: "510705",
name: "安州区",
pid: "5107",
},
{
id: "510722",
name: "三台县",
pid: "5107",
},
{
id: "510723",
name: "盐亭县",
pid: "5107",
},
{
id: "510725",
name: "梓潼县",
pid: "5107",
},
{
id: "510726",
name: "北川羌族自治县",
pid: "5107",
},
{
id: "510727",
name: "平武县",
pid: "5107",
},
{
id: "510781",
name: "江油市",
pid: "5107",
},
];
const result = convertToTreeFn(regions);
output.appendChild(getRegionDoms(result));
function getRegionDoms(regions) {
if (!regions || regions.length === 0) {
return;
}
const ul = document.createElement("ul");
regions.forEach((region) => {
const li = document.createElement("li");
const textNode = document.createTextNode(region.name);
li.appendChild(textNode);
const children = getRegionDoms(region.children);
if (children) {
li.appendChild(children);
}
ul.appendChild(li);
});
return ul;
}
</script>
</body>
</html>
js
function convertToTree(regions, rootId = "0") {
// TODO: 在这里写入具体的实现逻辑
// 将平铺的结构转化为树状结构,并将 rootId 下的所有子节点数组返回
// 如果不存在 rootId 下的子节点,则返回一个空数组
}
module.exports = convertToTree; // 检测需要,请勿删除
四、完成
function convertToTree(regions, rootId = "0") {
// TODO: 在这里写入具体的实现逻辑
// 将平铺的结构转化为树状结构,并将 rootId 下的所有子节点数组返回
// 如果不存在 rootId 下的子节点,则返回一个空数组
let newArr = []
//先遍历regions 如果pid和rootId相等那么将其加入newArr
regions.forEach(item => {
//如果存在pid和rootId相同
if (item.pid == rootId) {
newArr.push(item)
//递归调用 将id作为下一个rootId与pid相比
item.children = convertToTree(regions, item.id)
}
})
return newArr
}
module.exports = convertToTree; // 检测需要,请勿删除