这要从前几天看说起。
这份手册确实挺长,而且还是全英文,对于刚过四级的我来说,看着确实有些 "吃力"。这种 "吃力" 表现在,我经常看着看着就忘了自己看到哪了,对于前面看过的内容的印象特别模糊,于是我就在思考为什么会这样。
是有许多不认识的单词或不懂的语法吗?应该不是。事实上,一般技术文档除了一些专业术语外基本都是一些常见词汇,除了一些约定的或者是有典故的句子外基本上也没有比较复杂的语法;
是文章内容专业太强了吗?好像也不是,我一路读过来并没有感到有无法理解的地方。事实上,就我自己在学习过程中看到过的一些技术或项目的官方文档与相关的一些中文博客对比来看,往往这些 "官方文档" 讲解的更加简单,内容更加丰富。
是文章太长了吗?这个好像有点关系。本来自己目前刚过四级的英语水平还是在 9 年义务教育加 3 年高中教育的煎熬中获得的,这导致对英语产生了天然的排斥心理。看简短的英文文章还好,因为自己知道再坚持坚持就看完了;但是当看到一大段一大段,需要拉动滚动条好一会才能见底的英语文章时,我的内心是复杂的。
最后想了想,我觉得最关键的原因还是不会用英语去思考。就是说不能直接去领会一句话的意思,必须要将一句话在脑袋中翻译成中文才能去思考它传达的意思。再加上我翻译的速度还慢,虽然每句话在读的时候确实是明白了它的意思,但是当遇到较长文章的文章时,我需要在大脑中启动大量翻译操作,这就导致了阅读英语文章时很大的精力花费在了 "翻译" 上,对文章整体的逻辑无法把控。
于是我在知乎上搜索了相关问题,确实很多人都有这种疑问,并且也有人做了些解释,给了些解决办法。比如,。
好吧,上面扯了半天废话,我其实是想说,对一个写作者而言,除了将自己表达的内容清晰有条理的展现外,为文章构建出一个目录是非常重要的,并且这个目录最好是固定在屏幕的某个地方的,不会随着页面的滚动而滚动,它最好还能指示读者当前读到了哪一章节。这样能够让读者不会在 "浩瀚" 的文章中 "迷失"。
于是,昨天我花了一两个小时的时间为我的博文做了个目录,你稍微向下滚动一下这篇博文,应该就能看到。
在此将整个过程记录分享出来,希望能对有相同需求的你有所帮助。
目录需要用 JS 生成,首先当然是要先申请 JS 权限。这个需要在自己的管理页面点击申请,我这里已经申请成功了:
提取标题很简单,直接使用
API,即:
- document.querySelectorAll
- var aTitle = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
返回的是各个 h 标签对应的 dom 对象组成的数组,并且顺序正好与我们文章中各标题出现的顺序一致。
有了 "标题数组",我们可以遍历它,在遍历的每趟中,比较当前标题与上一趟的标题的级数:
举个栗子:假如我们有一个文章是这样子的:
- <h1>
- 白夜行
- </h1>
- <h2>
- 第一章
- </h2>
- <h3>
- 第一节
- </h3>
- <h3>
- 第二节
- </h3>
- <h3>
- 第三节
- </h3>
- <h2>
- 第二章
- </h2>
- <h3>
- 第一节
- </h3>
- <h3>
- 第二节
- </h3>
- <h2>
- 第三章
- </h2>
- <h3>
- 第一节
- </h3>
- <h3>
- 第二节
- </h3>
渲染出来是这个样子:
因此,我们需要得到这样的一个目录:
图中,一种颜色的矩形代表一个
,为了说明和编写代码的方便,我们为每一个
- ul
赋予一个
- ul
属性,其值等于它里面的标题的级数。比如上图中红色的
- level
的
- ul
应为 1,因为它里面的标题 "白夜行" 的级数是 1;而最里面的粉色的
- level
的级数应为 3,因为它里面的标题 "第一节" 和 "第二节" 是 3 级标题。
- ul
根据上面的分析,我们会从上至下依次遍历各个标题。但在遍历之前我们应该提前创建一个根
,遍历的第一个标题由于没有 "上一个标题",因此做特殊处理,直接插入到 " 当前
- ul
",也就是根
- ul
中;然后遍历到 "第一章",由于 "第一章" 的级数 (为 2) 大于 " 当前
- ul
"(红色 ul) 的级数 (为 1),因此需要 "向右缩进" 标题,即创建一个新的
- ul
,
- li
里面创建一个新的
- li
,将 "第一章" 放入这个新的
- ul
中,最后我们需要更新 " 当前
- ul
" 为颜色是绿色的那个
- ul
;接下来遍历到 "第一节",和 "第一章" 一样,也需要创建新的
- ul
,
- li
,并将 " 当前
- ul
" 更新为蓝色的
- ul
;再接着是 "第二节",由于 "第二节" 的级数(为 3)和 " 当前
- ul
"(蓝色的
- ul
)的级数一样,因此直接将 "第二节" 插入到 " 当前
- ul
"中;当遍历到" 第二章 "(级数为 2)时,此时的" 当前 ul" 是蓝色
- ul
(级数为 3),该
- ul
级数较大,因此需要 "向左缩进" 标题,即将 " 当前
- ul
""回退" 到上一 " 当前
- ul
"(绿色
- ul
),然后向 " 当前
- ul
" 中插入标题。以上就是 3 种所有的情况,后面的遍历过程都类似。
- ul
有了上面的分析,我们可以很快写出如下的构建目录的代码:
- function buildContents(rootId) {
- var aTitle = document.getElementById(rootId).querySelectorAll('h1, h2, h3, h4, h5, h6');
- var stack = [];
- var oRoot = document.createElement('ul');
- stack.push(oRoot);
- document.getElementById('contents').appendChild(oRoot);
- for (var i = 0; i < aTitle.length; i++) {
- var oTitle = aTitle[i];
- var level = parseInt(oTitle.nodeName.substring(1, 2)); // 当前标题的级数
- var oTop = stack[stack.length - 1]; // 得到栈顶元素
- if (i == 0)
- oTop.level = level;
- while (level < oTop.level) {
- // 向左缩进
- stack.pop();
- oTop = stack[stack.length - 1];
- }
- var oLi = document.createElement('li');
- oTop.appendChild(oLi);
- if (level == oTop.level) {
- // 直接插入
- oLi.textContent = oTitle.textContent;
- continue;
- } else if (level > oTop.level) {
- // 向右缩进
- var oUl = document.createElement('ul');
- oUl.level = level;
- oLi.appendChild(oUl);
- oLi.style.listStyle = 'none';
- var oChildLi = document.createElement('li');
- oChildLi.textContent = oTitle.textContent;
- oUl.appendChild(oChildLi);
- stack.push(oUl);
- oTop = oUl;
- continue;
- }
- }
- return oRoot;
- }
事实上,上面的代码是有 bug 的,或者说,它只能对 "标准" 目录进行处理,对于 "不标准" 的目录,处理起来就有问题了。比如我们将上面文章中的 "第一章" 删除,那么用它生成的目录是这个样子的:
显然不对,因为按道理应该是这个样子:
考虑一下问题产生的原因,是因为我们默认认为下一级标题一定在 " 当前
" 下,但事实上这还应该参考之后出现的标题的级数。比如在 1 级
- ul
后出现了一个 3 级标题,是否将该 3 级标题直接放在该
- ul
下,取决于之后的标题有没有 2 级标题:没有则直接插入;否则应该新建一个空的
- ul
,再在其内建立一个
- ul
用来放当前标题。这就要求我们必须提前知道所有的标题的级数,因此可以这么改进我们的代码:
- ul
以上代码和之前的代码思路都是一样的,只是代码的组织方式略有不同。另外我们为每个标题加入了链接,添加了锚点,这样可以点击某个标题直接定位到相应的内容。
接下来要做的是 "固定" 目录。如果你的博客有足够的空间,可以直接将生成的目录使用
固定在某个地方。但是如果没有合适的空间,你可以像我一样,将目录放在侧边栏内的底部,然后通过监听页面的滚动,当滚动到目录栏目时,将其 "固定" 住,不要再滚动了,代码大概是这样:
- position: fixed
- function stickUp(){
- var stickUpOffset = oContents.offsetTop;// oContents即你的目录的最外层容器dom对象
- document.onscroll = function(){
- if(window.scrollY >= stickUpOffset){
- fix();
- }else{
- static();
- }
- };
- var fixed;
- function fix(){
- if(fixed) return;
- oSideBar.style.top = (oSideBar.offsetTop - oContents.offsetTop) + 'px'; // oSideBar为侧边栏dom对象
- oSideBar.style.position = 'fixed';
- fixed = true;
- }
- function static(){
- oSideBar.style.position = 'static';
- fixed = false;
- }
- }
为了能在目录中指示文章滚动到了哪儿,我们同样需要监听文章的滚动,然后将离当前滚动位置最近的之前的标题在目录中高亮显示。
先写一个高亮的 CSS class,然后将该 class 加在合适的位置即可:
- .active{
- color: yellow;
- }
可以这么加 class:
以上便是整个生成目录的步骤,只贴了大概的代码,因为每个人的博客模板可能不同,剩余的就需要根据自己的模板去写了。
来源: http://www.cnblogs.com/dongkuo/p/6491816.html