需求
给定一个形式如下的html:
<div id='nav'>
<li>测试测试</li>
</div>
<div id="article">
<h1>1、一级标题测试</h1>
<p>test 水电费水电费水电费是 水胜多负少是水电费水电费是</p>
<p>test 水电费水电费水电费是 水电费水电费 胜多负少是水电费水电费是</p>
<h2>1.1、二级标题</h2>
<p>test 水电费水电费水电费是 水电费水电费 胜多负少是水电费水电费是</p>
<p>test 水电费水电费水电费是 水电费水电费 胜多负少是水电费水电费是</p>
<h3>1.1.1、三级标题</h3>
<p>test 水电费水电费水电费是 水电费水电费 胜多负少是水电费水电费是</p>
<p>test 水电费水电费水电费是 水电费水电费 胜多负少是水电费水电费是</p>
<h3>1.1.2、三级标题</h3>
<p>test 水电费水电费水电费是 水电费水电费 胜多负少是水电费水电费是</p>
<p>test 水电费水电费水电费是 水电费水电费 胜多负少是水电费水电费是</p>
<h2>1.2、二级标题</h2>
<p>test 水电费水电费水电费是 水电费水电费 胜多负少是水电费水电费是</p>
<p>test 水电费水电费水电费是 水电费水电费 胜多负少是水电费水电费是</p>
<h2>1.3、二级标题</h2>
<p>test 水电费水电费水电费是 水电费水电费 胜多负少是水电费水电费是</p>
<p>test 水电费水电费水电费是 水电费水电费 胜多负少是水电费水电费是</p>
<h1>2、一级标题测试</h1>
<p>test 水电费水电费水电费是 水电费水电费 胜多负少是水电费水电费是</p>
<p>test 水电费水电费水电费是 水电费水电费 胜多负少是水电费水电费是</p>
<p>test 水电费水电费水电费是 水电费水电费 胜多负少是水电费水电费是</p>
<h2>2.1、二级标题</h2>
<p>test 水电费水电费水电费是 水电费水电费 胜多负少是水电费水电费是</p>
<p>test 水电费水电费水电费是 水电费水电费 胜多负少是水电费水电费是</p>
<h2>2.2、二级标题</h2>
<p>test 水电费水电费水电费是 水电费水电费 胜多负少是水电费水电费是</p>
<p>test 水电费水电费水电费是 水电费水电费 胜多负少是水电费水电费是</p>
<h2>2.3、二级标题</h2>
<p>test 水电费水电费水电费是 水电费水电费 胜多负少是水电费水电费是</p>
<p>test 水电费水电费水电费是 水电费水电费 胜多负少是水电费水电费是</p>
</div>
得到文章的导航如下图:
解决方案
实现思路:
- 根据h标签确定一级导航,可以是h1到h9中任意一个。
- 将生成一级导航需要的数据(这里用对象表示,包含id,导航内容)存入数组。
-
用上面生成的数组采用递归的方式逐级构建导航,形成的完整的导航数据结构,如下图:
4、由上一步得到的数据,递归渲染出导航。
代码如下:
//此处省略了引入jquery代码。。。。
<script>
$(document).ready(function () {
var href_arr = [];
//从h1开始查找到h9,找到一个就作为一级导航,然后开始构建
for(var level=1;level<10;level++){
$("#article h"+level).each(function (i) {
var obj = {};
var h_id = (i+1)+'_help_'+level+'_'+(i+1);
$(this).attr('id',h_id);
obj.id = h_id;
obj.content = $(this).text();
href_arr.push(obj);
});
if(href_arr && href_arr.length>0){
build_level(href_arr,level);
//渲染导航
render(href_arr);
break;
}
}
//渲染导航
function render(href_arr){
var html = render_nav(href_arr);
$("#nav").append(html);
}
function render_nav(href_arr){
var html = '<ul>';
for(var i=0;i<href_arr.length;i++){
html+= "<li><a href='#"+href_arr[i].id+"'>"+href_arr[i].content;
if(href_arr[i].next_level && href_arr[i].next_level.length>0){
html += render_nav(href_arr[i].next_level,html)
}
html+="</a></li>";
}
html+='</ul>';
return html;
}
//构建层级关系
function build_level(arr,level){
for(var i=0;i<arr.length;i++){
arr[i].next_level = [];
var next_level_nodes = [];
if(i!=arr.length-1){
next_level_nodes = $("#"+arr[i].id).nextUntil("#"+arr[i+1].id,'h'+(level+1));
}else {
next_level_nodes = $("#"+arr[i].id).nextAll('h'+(level+1));
}
if(next_level_nodes && next_level_nodes.length>0){
next_level_nodes.each(function (j) {
var obj = {};
var h_id = (i+1)+'_help_'+(level+1)+'_'+(j+1);
$(this).attr('id',h_id);
obj.id = h_id;
obj.content = $(this).text();
arr[i].next_level.push(obj);
});
if(arr[i].next_level && arr[i].next_level.length > 0){
build_level(arr[i].next_level,level+1)
}
}
}
}
});
</script>
应用场景
后端通过富文本编辑器,如ckeditor,发布新闻或文章页面,当页面内容比较多的时候,生成导航方便读者浏览。
使用富文本编辑器可以很方便的上传图、视频、文件,个人觉得比markdown更好用。
后记
其实,最开始的需求是快速构建网站说明文档,所以看了一下docsify,确实是个好东东,但是采用的markdown,传图、视频、文件好像不太方便,对于写开发者帮助文章很适用,还有gitbook听说也不错,后续深入了解一下!