zzy

2025.2.13

多级标题

效果展示

语法说明

  • markdown 中, 标题的设置由符号 # 控制. 多级标题则由 # 的数量控制, 即:

    1
    2
    3
    4
    # 一级标题
    ## 二级标题
    ### 三级标题
    ...

实现思路

映射法则

  • 对应到 HTML 中, 就是 h1 系列标签:
    • # - <h1> </h1>
    • ## - <h2> </h2>
    • ### - <h3> </h3>

核心逻辑

  • 因此只要获取行首的 # 标识符, 得到其数量即可, 核心逻辑如下:

    1
    2
    let n = "#*n".length; // 其中 `#*n`仅为示意 代表n个# 
    console.log(`<h${n}> </h${n}>`); // 使用了模板字符串 详见 `知识补充` - `模板字符串` 部分查看
  • 引入正则

    详见 知识补充 - 正则 部分查看

    1
    2
    3
    4
    // 假设已经获得了要处理的行 mystr
    let re = /^#+\s/;
    let n = i.match(/#+\s/)[0].length;
    let html = `<h${n}>${mystr}</h${n}>`;
  • 最后把结果设置到输出区域即可

    1
    2
    const output = document.getElementById('output');
    output.innerHTML = html;

完整流程

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
// 监听输入并输出到预览
document.addEventListener('DOMContentLoaded', (event) => {
const input = document.getElementById('input');
const output = document.getElementById('output');
input.addEventListener('input', (event) => {
// 处理输入
output.innerHTML = handleinput(input.value);
});
});

// 处理输入流程
function handleinput(ori){
// 去空
let oris = ori.split('\n');
let filter = []
for (let i of oris){
if (i){
filter = [...filter, i]
}
};
// 多级标题
let title = []
for (let i of filter) {
if (i[0] == '#' && /#+\s/.test(i)){
let n = i.match(/#+\s/)[0].length;
console.log(i.match(/#+\s/)[0])
i = `<h${n-1}>${i.slice(n)}</h${n-1}>`
// console.log(i)
}
title = [...title, i]
};
// console.log(title)

let rows = []
for (let i of title){
if (i){
rows = [...rows, `<p>${i}</p>`]
}
};
// 分行

md = rows.join('\n')
return md
};

htmlcss 无变化

代码展示

项目结构

  • index.html
  • css
    • index.css
  • js
    • index.js

index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>md</title>
<link rel="stylesheet" href="./css/index.css">
<script src="./js/index.js"></script>
</head>

<body>
<div class="container">
<div class="input">
<textarea id="input"></textarea>
</div>
<div class="output">
<span id="output"></span>
</div>
</div>
</body>

</html>

index.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
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

.container {
display: flex;
}

.input {
flex: 1;
margin: 16px;
}

.output {
flex: 1;
margin: 16px;
}

.input #input {
height: 200px;
width: 100%;
padding: 10px;
}

.output #output {
padding: 10px;
}

index.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
42
43
document.addEventListener('DOMContentLoaded', (event) => {
const input = document.getElementById('input');
const output = document.getElementById('output');
input.addEventListener('input', (event) => {
// 考虑添加防抖

output.innerHTML = handleinput(input.value);
});
});

function handleinput(ori){
// 去空
let oris = ori.split('\n');
let filter = []
for (let i of oris){
if (i){
filter = [...filter, i]
}
};
// 多级标题
let title = []
for (let i of filter) {
if (i[0] == '#' && /#+\s/.test(i)){
let n = i.match(/#+\s/)[0].length;
console.log(i.match(/#+\s/)[0])
i = `<h${n-1}>${i.slice(n)}</h${n-1}>`
// console.log(i)
}
title = [...title, i]
};
// console.log(title)

let rows = []
for (let i of title){
if (i){
rows = [...rows, `<p>${i}</p>`]
}
};
// 分行

md = rows.join('\n')
return md
};
本文作者:zzy
本文链接:http://周梓煜.com/2025/02/18/Re-从零开始的markdown编辑器/md-3/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可