JS生成HTML的目录

前言

生成目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function getCatalog(className){
let showDom = document.querySelector("."+className);
// 获取所有标题元素
const headings = showDom.querySelectorAll('h1, h2, h3, h4, h5, h6');
let num = 0;
let titleArr = Array.from(headings).map(heading=>{
num+=1;
let cName = "z_catalog_"+num;
heading.classList.add(cName);
const level = parseInt(heading.tagName.charAt(1));
const title = heading.textContent;
return {
level:level,
title:title,
className:cName
}
});
return titleArr
}

let catalogArr = getCatalog("v-show-content");
console.info(catalogArr);

滚动到指定位置

1
2
3
4
5
6
function scrollToDiv(className) {
let mDom = document.querySelector("."+className);
mDom.scrollIntoView({ behavior: "smooth" });
}

scrollToDiv("z_catalog_5")

Vue项目中对接

模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<div class="catalog" v-show="showCatalog">
<div class="catalog_title">
<div v-show="showCatalog">目录</div>
<div class="catalog_btn" @click="showCatalog = !showCatalog">
<Icon type="md-arrow-round-forward" />
</div>
</div>
<div class="catalog_content" v-show="showCatalog">
<div
v-for="(catalog, index) in catalogArr"
:key="index"
class="catalog_item"
:style="{ 'margin-left': (catalog.level - 1) * 16 + 'px' }"
@click="scrollToDiv(catalog.className)"
>
{{ catalog.title }}
</div>
</div>
</div>

<div class="show_catalog" v-show="!showCatalog" @click="showCatalog = true">
<Icon type="md-arrow-round-back" />
</div>

JS

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
{
data() {
return {
showCatalog: true,
catalogArr: [],
};
},
async mounted() {
this.init();
},
methods: {
async init() {
await this.$nextTick();
this.catalogArr = this.getCatalog("v-show-content");
},
getCatalog(className) {
let showDom = document.querySelector("." + className);
// 获取所有标题元素
const headings = showDom.querySelectorAll(
"h1, h2, h3, h4, h5, h6"
);
let num = 0;
return Array.from(headings).map((heading) => {
num += 1;
let cName = "z_catalog_" + num;
heading.classList.add(cName);
const level = parseInt(heading.tagName.charAt(1));
const title = heading.textContent;
return {
level: level,
title: title,
className: cName,
};
});
},
scrollToDiv(className) {
let mDom = document.querySelector("." + className);
mDom.scrollIntoView({ behavior: "smooth" });
},
},
};

CSS

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
.catalog {
position: absolute;
width: 200px;
max-height: 60%;
box-shadow: 4px 4px 10px 2px #ddd;
top: 170px;
right: 20px;
z-index: 20;
background: white;
display: flex;
flex-direction: column;
border-radius: 8px;
overflow: hidden;

.catalog_title {
font-weight: bold;
padding: 6px 10px 6px 14px;
flex: none;
display: flex;
align-items: center;
justify-content: space-between;

.catalog_btn {
font-weight: normal;
cursor: pointer;
border-radius: 20px;
padding-left: 10px;
font-size: 20px;
}

.catalog_btn:hover {
color: dodgerblue;
}
}

.catalog_content {
flex: auto;
overflow-y: auto;
padding: 20px;
border-top: 1px solid #ddd;

.catalog_item {
cursor: pointer;
padding-bottom: 6px;
}

.catalog_item:hover {
color: dodgerblue;
}
}
}

.show_catalog {
position: absolute;
height: 40px;
width: 40px;
background: white;
right: 0;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
border-radius: 10px 0 0 10px;
box-shadow: 4px 4px 10px 2px #ddd;
font-size: 20px;
}

.show_catalog:hover {
background: var(--primary);
color: white;
}