曾经有个项目,前端静态资源服务器的HTML文件全部在同一层目录中,文件名按模块以“-”分隔。随着项目的扩大,文件数不断增加,到最后多达200+个页面文件。在需要定位某个页面时,即便通过搜索,也是一件很头疼的事情。为此需要寻找一种更方便定位、更直观的方式。常见的文章、书籍的树状目录索引便是普遍的方式。
思路
首先,获取到所有header,利用jQuery的:header即可。然后对其进行遍历,将层级和父子关系等信息附加到节点上。因为是层级关系,这里有个默认的前提条件,上下级之间是连续的,也即下一节点是上一节点的直接子节点,或者是上一节点的任一父节点的兄弟节点。在此条件下,经过2层迭代,即可生成所需要节点数据。
然后,作为入口,对所有节点进行遍历,找到树根的H1节点,对其进行递归,遍历出属于该根节点的目录树。每个递归过程,判断当前节点的兄弟节点关系,并依据判断结果对当前节点进行格式化输出,将其附加到节点信息中。递归结束后,对当前节点进行输出,即为预期所需要的内容。
实现
根据上述思路,实现如下:
javascriptCopy code- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
function initTree ($docDom) {
var nodesArr = [], i = 0, j = 0, $headers = $docDom.find(':header');
$.each($headers.prevObject, function (idx, v) {
var $curHeader = $(v), curLevel = parseInt(v.tagName.charAt(1), 10), nodeObj = {};
nodeObj.name = $curHeader.attr('name');
nodeObj.text = $curHeader.html();
nodeObj.link = '<a href="#' + $curHeader.attr('name') + '">' + $curHeader.html() + '</a>';
nodeObj.level = curLevel;
nodeObj.parent = '';
nodeObj.children = [];
nodeObj.childrenIndex = [];
nodeObj.index = idx;
nodeObj.parentIndex = -1;
nodeObj.padStr = '';
nodesArr.push(nodeObj);
});
for ( i = 1; i < nodesArr.length; i++) {
if (nodesArr[i].level === nodesArr[i - 1].level + 1) {
nodesArr[i].parent = nodesArr[i - 1].name;
nodesArr[i].parentIndex = nodesArr[i - 1].index;
nodesArr[i - 1].children.push(nodesArr[i].name);
nodesArr[i - 1].childrenIndex.push(nodesArr[i].index);
} else if (nodesArr[i].level <= nodesArr[i - 1].level) {
for ( j = i - 2; j >= 0; j--) {
if (nodesArr[i].level === nodesArr[j].level + 1) {
nodesArr[i].parent = nodesArr[j].name;
nodesArr[i].parentIndex = nodesArr[j].index;
nodesArr[j].children.push(nodesArr[i].name);
nodesArr[j].childrenIndex.push(nodesArr[i].index);
break;
}
}
}
}
return nodesArr;
}
function hasSiblings (dataArr, curNode) {
//1-父节点有兄弟节点,2-父节点无兄弟节点,3-父节点为根节点,4-当前节点为根节点
var result = 0;
if (curNode.parentIndex > -1) {
if (dataArr[curNode.parentIndex].parentIndex > -1) {
result = (dataArr[dataArr[curNode.parentIndex].parentIndex].children.length > 1) ? 1 : 2;
} else {
result = 3;
}
} else {
result = 4;
}
return result;
}
function isLastSibling (dataArr, curNode) {
//1-父节点为最后一个兄弟节点,2-父节点非最后一个兄弟节点,3-父节点为根节点,4-当前节点为根节点
var childNodes, result;
if (curNode.parentIndex > -1) {
if (dataArr[curNode.parentIndex].parentIndex > -1) {
childNodes = dataArr[dataArr[curNode.parentIndex].parentIndex].children;
result = ($.inArray(dataArr[curNode.parentIndex].name, childNodes) === childNodes.length - 1) ? 1 : 2;
} else {
result = 3;
}
} else {
result = 4;
}
return result;
}
function iterateChildren (dataArr, curNode) {
$.each(curNode.childrenIndex, function (i, v) {
var tmpParent = dataArr[v], siblingFlag, lastSiblingFlag;
while (tmpParent.parentIndex > -1) {
siblingFlag = hasSiblings(dataArr, tmpParent);
lastSiblingFlag = isLastSibling(dataArr, tmpParent);
if (siblingFlag === 1 && lastSiblingFlag === 2) {
dataArr[v].padStr = '┆ ' + dataArr[v].padStr;
} else if (siblingFlag === 1 && lastSiblingFlag === 1) {
dataArr[v].padStr = ' ' + dataArr[v].padStr;
} else if (siblingFlag === 2) {
dataArr[v].padStr = ' ' + dataArr[v].padStr;
} else if (siblingFlag === 3 || siblingFlag === 4) {
break;
}
tmpParent = dataArr[tmpParent.parentIndex];
}
if (i === curNode.childrenIndex.length - 1) {
dataArr[v].padStr += '└┄';
} else {
dataArr[v].padStr += '├┄';
}
iterateChildren(dataArr, dataArr[v]);
});
}
function displayTree ($docDom) {
var nodesArr = initTree($docDom);
for ( i = 0; i < nodesArr.length; i++) {
if (nodesArr[i].level === 1) {
iterateChildren(nodesArr, nodesArr[i]);
}
console.log(nodesArr[i].padStr + nodesArr[i].link);
}
}
function initTree ($docDom) {
var nodesArr = [], i = 0, j = 0, $headers = $docDom.find(':header');
$.each($headers.prevObject, function (idx, v) {
var $curHeader = $(v), curLevel = parseInt(v.tagName.charAt(1), 10), nodeObj = {};
nodeObj.name = $curHeader.attr('name');
nodeObj.text = $curHeader.html();
nodeObj.link = '' + $curHeader.html() + '';
nodeObj.level = curLevel;
nodeObj.parent = '';
nodeObj.children = [];
nodeObj.childrenIndex = [];
nodeObj.index = idx;
nodeObj.parentIndex = -1;
nodeObj.padStr = '';
nodesArr.push(nodeObj);
});
for ( i = 1; i < nodesArr.length; i++) {
if (nodesArr[i].level === nodesArr[i - 1].level + 1) {
nodesArr[i].parent = nodesArr[i - 1].name;
nodesArr[i].parentIndex = nodesArr[i - 1].index;
nodesArr[i - 1].children.push(nodesArr[i].name);
nodesArr[i - 1].childrenIndex.push(nodesArr[i].index);
} else if (nodesArr[i].level <= nodesArr[i - 1].level) {
for ( j = i - 2; j >= 0; j--) {
if (nodesArr[i].level === nodesArr[j].level + 1) {
nodesArr[i].parent = nodesArr[j].name;
nodesArr[i].parentIndex = nodesArr[j].index;
nodesArr[j].children.push(nodesArr[i].name);
nodesArr[j].childrenIndex.push(nodesArr[i].index);
break;
}
}
}
}
return nodesArr;
}
function hasSiblings (dataArr, curNode) {
//1-父节点有兄弟节点,2-父节点无兄弟节点,3-父节点为根节点,4-当前节点为根节点
var result = 0;
if (curNode.parentIndex > -1) {
if (dataArr[curNode.parentIndex].parentIndex > -1) {
result = (dataArr[dataArr[curNode.parentIndex].parentIndex].children.length > 1) ? 1 : 2;
} else {
result = 3;
}
} else {
result = 4;
}
return result;
}
function isLastSibling (dataArr, curNode) {
//1-父节点为最后一个兄弟节点,2-父节点非最后一个兄弟节点,3-父节点为根节点,4-当前节点为根节点
var childNodes, result;
if (curNode.parentIndex > -1) {
if (dataArr[curNode.parentIndex].parentIndex > -1) {
childNodes = dataArr[dataArr[curNode.parentIndex].parentIndex].children;
result = ($.inArray(dataArr[curNode.parentIndex].name, childNodes) === childNodes.length - 1) ? 1 : 2;
} else {
result = 3;
}
} else {
result = 4;
}
return result;
}
function iterateChildren (dataArr, curNode) {
$.each(curNode.childrenIndex, function (i, v) {
var tmpParent = dataArr[v], siblingFlag, lastSiblingFlag;
while (tmpParent.parentIndex > -1) {
siblingFlag = hasSiblings(dataArr, tmpParent);
lastSiblingFlag = isLastSibling(dataArr, tmpParent);
if (siblingFlag === 1 && lastSiblingFlag === 2) {
dataArr[v].padStr = '┆ ' + dataArr[v].padStr;
} else if (siblingFlag === 1 && lastSiblingFlag === 1) {
dataArr[v].padStr = ' ' + dataArr[v].padStr;
} else if (siblingFlag === 2) {
dataArr[v].padStr = ' ' + dataArr[v].padStr;
} else if (siblingFlag === 3 || siblingFlag === 4) {
break;
}
tmpParent = dataArr[tmpParent.parentIndex];
}
if (i === curNode.childrenIndex.length - 1) {
dataArr[v].padStr += '└┄';
} else {
dataArr[v].padStr += '├┄';
}
iterateChildren(dataArr, dataArr[v]);
});
}
function displayTree ($docDom) {
var nodesArr = initTree($docDom);
for ( i = 0; i < nodesArr.length; i++) {
if (nodesArr[i].level === 1) {
iterateChildren(nodesArr, nodesArr[i]);
}
console.log(nodesArr[i].padStr + nodesArr[i].link);
}
}
调用
javascriptCopy code- 1
displayTree(...);
displayTree(...);
输入1:
xmlCopy code- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
<h1 name="t1">1</h1>
<h2 name="t2">2</h2>
<h3 name="t3">3</h3>
<h2 name="t4">4</h2>
<h3 name="t5">5</h3>
<h4 name="t16">16</h4>
<h5 name="t17">17</h5>
<h6 name="t18">18</h6>
<h3 name="t6">6</h3>
<h2 name="t19">19</h2>
<h1 name="t7">7</h1>
<h2 name="t8">8</h2>
<h3 name="t9">9</h3>
<h3 name="t10">10</h3>
<h3 name="t11">11</h3>
<h2 name="t12">12</h2>
<h2 name="t13">13</h2>
<h3 name="t14">14</h3>
<h1 name="t15">15</h1>
1
2
3
4
5
16
17
18
6
19
7
8
9
10
11
12
13
14
15
输出1:
htmlCopy code- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
<a href="#t1">1</a>
├┄<a href="#t2">2</a>
┆ └┄<a href="#t3">3</a>
├┄<a href="#t4">4</a>
┆ ├┄<a href="#t5">5</a>
┆ ┆ └┄<a href="#t16">16</a>
┆ ┆ └┄<a href="#t17">17</a>
┆ ┆ └┄<a href="#t18">18</a>
┆ └┄<a href="#t6">6</a>
└┄<a href="#t19">19</a>
<a href="#t7">7</a>
├┄<a href="#t8">8</a>
┆ ├┄<a href="#t9">9</a>
┆ ├┄<a href="#t10">10</a>
┆ └┄<a href="#t11">11</a>
├┄<a href="#t12">12</a>
└┄<a href="#t13">13</a>
└┄<a href="#t14">14</a>
<a href="#t15">15</a>
输入2:
xmlCopy code- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
<h1 name="t1">1</h1>
<h2 name="t2">2</h2>
<h3 name="t3">3</h3>
<h4 name="t4">4</h4>
<h5 name="t5">5</h5>
<h6 name="t6">6</h6>
<h6 name="t7">7</h6>
<h5 name="t8">8</h5>
<h6 name="t9">9</h6>
<h6 name="t10">10</h6>
<h4 name="t11">11</h4>
<h5 name="t12">12</h5>
<h6 name="t13">13</h6>
<h6 name="t14">14</h6>
<h5 name="t15">15</h5>
<h6 name="t16">16</h6>
<h6 name="t17">17</h6>
<h3 name="t18">18</h3>
<h4 name="t19">19</h4>
<h5 name="t20">20</h5>
<h6 name="t21">21</h6>
<h6 name="t22">22</h6>
<h5 name="t23">23</h5>
<h6 name="t24">24</h6>
<h6 name="t25">25</h6>
<h4 name="t26">26</h4>
<h5 name="t27">27</h5>
<h6 name="t28">28</h6>
<h6 name="t29">29</h6>
<h5 name="t30">30</h5>
<h6 name="t31">31</h6>
<h6 name="t32">32</h6>
<h2 name="t33">33</h2>
<h3 name="t34">34</h3>
<h4 name="t35">35</h4>
<h5 name="t36">36</h5>
<h6 name="t37">37</h6>
<h6 name="t38">38</h6>
<h5 name="t39">39</h5>
<h6 name="t40">40</h6>
<h6 name="t41">41</h6>
<h4 name="t42">42</h4>
<h5 name="t43">43</h5>
<h6 name="t44">44</h6>
<h6 name="t45">45</h6>
<h5 name="t46">46</h5>
<h6 name="t47">47</h6>
<h6 name="t48">48</h6>
<h3 name="t49">49</h3>
<h4 name="t50">50</h4>
<h5 name="t51">51</h5>
<h6 name="t52">52</h6>
<h6 name="t53">53</h6>
<h5 name="t54">54</h5>
<h6 name="t55">55</h6>
<h6 name="t56">56</h6>
<h4 name="t57">57</h4>
<h5 name="t58">58</h5>
<h6 name="t59">59</h6>
<h6 name="t60">60</h6>
<h5 name="t61">61</h5>
<h6 name="t62">62</h6>
<h6 name="t63">63</h6>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
输出2(二叉树):
htmlCopy code- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
<a href="#t1">1</a>
├┄<a href="#t2">2</a>
┆ ├┄<a href="#t3">3</a>
┆ ┆ ├┄<a href="#t4">4</a>
┆ ┆ ┆ ├┄<a href="#t5">5</a>
┆ ┆ ┆ ┆ ├┄<a href="#t6">6</a>
┆ ┆ ┆ ┆ └┄<a href="#t7">7</a>
┆ ┆ ┆ └┄<a href="#t8">8</a>
┆ ┆ ┆ ├┄<a href="#t9">9</a>
┆ ┆ ┆ └┄<a href="#t10">10</a>
┆ ┆ └┄<a href="#t11">11</a>
┆ ┆ ├┄<a href="#t12">12</a>
┆ ┆ ┆ ├┄<a href="#t13">13</a>
┆ ┆ ┆ └┄<a href="#t14">14</a>
┆ ┆ └┄<a href="#t15">15</a>
┆ ┆ ├┄<a href="#t16">16</a>
┆ ┆ └┄<a href="#t17">17</a>
┆ └┄<a href="#t18">18</a>
┆ ├┄<a href="#t19">19</a>
┆ ┆ ├┄<a href="#t20">20</a>
┆ ┆ ┆ ├┄<a href="#t21">21</a>
┆ ┆ ┆ └┄<a href="#t22">22</a>
┆ ┆ └┄<a href="#t23">23</a>
┆ ┆ ├┄<a href="#t24">24</a>
┆ ┆ └┄<a href="#t25">25</a>
┆ └┄<a href="#t26">26</a>
┆ ├┄<a href="#t27">27</a>
┆ ┆ ├┄<a href="#t28">28</a>
┆ ┆ └┄<a href="#t29">29</a>
┆ └┄<a href="#t30">30</a>
┆ ├┄<a href="#t31">31</a>
┆ └┄<a href="#t32">32</a>
└┄<a href="#t33">33</a>
├┄<a href="#t34">34</a>
┆ ├┄<a href="#t35">35</a>
┆ ┆ ├┄<a href="#t36">36</a>
┆ ┆ ┆ ├┄<a href="#t37">37</a>
┆ ┆ ┆ └┄<a href="#t38">38</a>
┆ ┆ └┄<a href="#t39">39</a>
┆ ┆ ├┄<a href="#t40">40</a>
┆ ┆ └┄<a href="#t41">41</a>
┆ └┄<a href="#t42">42</a>
┆ ├┄<a href="#t43">43</a>
┆ ┆ ├┄<a href="#t44">44</a>
┆ ┆ └┄<a href="#t45">45</a>
┆ └┄<a href="#t46">46</a>
┆ ├┄<a href="#t47">47</a>
┆ └┄<a href="#t48">48</a>
└┄<a href="#t49">49</a>
├┄<a href="#t50">50</a>
┆ ├┄<a href="#t51">51</a>
┆ ┆ ├┄<a href="#t52">52</a>
┆ ┆ └┄<a href="#t53">53</a>
┆ └┄<a href="#t54">54</a>
┆ ├┄<a href="#t55">55</a>
┆ └┄<a href="#t56">56</a>
└┄<a href="#t57">57</a>
├┄<a href="#t58">58</a>
┆ ├┄<a href="#t59">59</a>
┆ └┄<a href="#t60">60</a>
└┄<a href="#t61">61</a>
├┄<a href="#t62">62</a>
└┄<a href="#t63">63</a>
1
├┄2
┆ ├┄3
┆ ┆ ├┄4
┆ ┆ ┆ ├┄5
┆ ┆ ┆ ┆ ├┄6
┆ ┆ ┆ ┆ └┄7
┆ ┆ ┆ └┄8
┆ ┆ ┆ ├┄9
┆ ┆ ┆ └┄10
┆ ┆ └┄11
┆ ┆ ├┄12
┆ ┆ ┆ ├┄13
┆ ┆ ┆ └┄14
┆ ┆ └┄15
┆ ┆ ├┄16
┆ ┆ └┄17
┆ └┄18
┆ ├┄19
┆ ┆ ├┄20
┆ ┆ ┆ ├┄21
┆ ┆ ┆ └┄22
┆ ┆ └┄23
┆ ┆ ├┄24
┆ ┆ └┄25
┆ └┄26
┆ ├┄27
┆ ┆ ├┄28
┆ ┆ └┄29
┆ └┄30
┆ ├┄31
┆ └┄32
└┄33
├┄34
┆ ├┄35
┆ ┆ ├┄36
┆ ┆ ┆ ├┄37
┆ ┆ ┆ └┄38
┆ ┆ └┄39
┆ ┆ ├┄40
┆ ┆ └┄41
┆ └┄42
┆ ├┄43
┆ ┆ ├┄44
┆ ┆ └┄45
┆ └┄46
┆ ├┄47
┆ └┄48
└┄49
├┄50
┆ ├┄51
┆ ┆ ├┄52
┆ ┆ └┄53
┆ └┄54
┆ ├┄55
┆ └┄56
└┄57
├┄58
┆ ├┄59
┆ └┄60
└┄61
├┄62
└┄63