开发:折叠式目录

字数统计: 2.1k 阅读时间: 4 mins 访问次数: ... 评论统计: ...

  是说我也病倒了,可恶,人类的身体真是脆弱啊【振声
  昨天折腾造语折腾到凌晨四五点,然后眼前开始忽明忽暗脑子像进了水一样摇摇晃晃,我以为我是用脑过度就咣当倒在床上睡了,结果一觉醒来发现:喜报,我发烧了!
  以及天冷了在床上搭了个桌子把鼠标键盘都挪远了,大概是手机玩太多了看屏幕有点费劲……总之除了睡觉以外好像做什么都不太行的样子。
  但是因为昨天写造语文档哗啦啦列了一大串目录我还是决定要搞一个和 next 一样的自动折叠展开目录……所以我为什么不一开始就直接用 next 算了……

事前吐槽

img-right

  本来我还想给滚动条做个平滑效果的,结果搜了半天都是原生滚动条的事件,尝试搜索 Perfect-scrollbar 的中文文档,找到了 这么个东西
  你好,到底是你不会中文还是我不会中文?

  还有这么个东西→
  那你 close 你 emoji 呢?

  总之平滑滚动的功能就先放一边了……但是我整个页面用的都是这个第三方滚动条,估计 JS 自带的那些监听事件不一定管用,最后大概率还是要改它的源码的。
  哎反正今天眼睛和脑子都不太好使,先把思路记下来放着有空再说。

  说起来这个两侧 float 的图片和标题相接的位置似乎有一些问题,如果图片高度太大文字内容太少的话会和下一个标题咬在一起,就不太好看的样子……但是 clear:both 之后似乎把原本设置的上下 margin 也一起忽略了,暂时只能多 BB 一点废话把这个问题掩盖过去……嗯,这么多废话差不多就够了【

功能设计

需求

  1. 右侧 TOC 的二级目录默认隐藏(对应的是正文的 H4 内容)
  2. 滚动到相应一级目录时展开相应的二级目录
  3. 滚动到下一条目录时取消激活之前的目录

思路

  • 触发时间:滚动停止 0.5s 后
    • 遍历所有标题链接 $(.headerlink).each,执行
      • 如果链接与父元素的相对高度 .positon().top - 父元素的滚动距离 scrollTop < 0,执行
        • var x = $('.toc-link[href*=' + 当前标题链接 + ']');
          // 获取 toc 中能跳转到当前标题的链接
        • x.siblings('a').removeClass('active');
          // 为所有同级元素取消激活状态
        • x.addClass('active');
          // 激活当前链接

  昨晚睡前是这样想的,睡醒琢磨了一下感觉不对,如果这样写的话每一个已经滚出屏幕外的链接也要跑一遍「为所有同级元素取消激活状态」的流程,请求就太过冗余了。
  尝试使用 css 的 last-child 伪类,发现没办法定位到我想要的元素,每个父元素下的最后一个链接都会被选中,结果就是多个标题一起亮起。查询了一下 jquery 选择器,发现可以用 :last 选中单个同位子元素。
  说起来好像蛮绕的但是我也不知道怎么用中文表达了【总之菜鸟教程的实例在 这里

测试

测试用二级标题 1

  不知道发生了什么神秘 bug 总之 .positon().top 输出的不是标题和 .article-entry 之间的距离而是与窗口的某条不可见基准线之间的距离……仔细看了一下等于 0 的时候似乎是和网页的主标题(就是旁边那个无色人间)对齐的,至于到底为什么会这样,我也不敢深究……
  总之按结论来看这个输出数据 < 0 的时候就可以进行下一步操作了,嗯【
  另外因为猜到滚动条触发的事件请求会特别多 以及我的代码写得像屎山,于是抄了一个 定时器 用来过滤多余的请求,然而电脑还是蜜汁卡顿,打开任务管理器研究了半天发现是 QQ 在疯狂读写硬盘 :4o-4: 退出之后就不卡了,emmmm

测试用二级标题 2

  于是当你看到这篇文章的时候这堆屎山代码已经顺利跑起来了!
  其实我大概研究了一下 next 的目录类名,大胆推测一下它的源码大概也和我差不多,甚至可能比我还…… 毕竟它的目录展开是没有动画效果的诶
  大概的实现方法和功能设计里的一样,但是遇到几个坑点:

  1. 主题生成的链接是 html 代码,获取标题链接的 title 之后需要经过转义才能成功匹配到 toc 上的按钮
  2. 直接为所有同级元素 removeClass 会造成 css 动画抖动,最直观的就是这个折起来的二级目录上蹿下跳,最后实现方法是这个样子的:
    1
    2
    3
    4
    5
    $('.toc-level-3 >.toc-link').not('.visited-h3:last').removeClass('active');
    $('.toc-level-4 >.toc-link').not('.visited-h4:last').removeClass('active');
    $('.visited-h3:last, .visited-h4:last').addClass('active');
    $('.toc-link').not('.visited-h3.active').next().slideUp('0.3s');
    $('.visited-h3.active').next().slideDown('0.3s');
    总之就是为一级目录(h3)和二级目录(h4)添加不同的 visited 类名,然后为二者的最后一个元素都添加上 .active class;然后用 .not() 从选择器中排除最后一个元素,再为剩下的元素都删去 .active class。
  3. 手机页面下目录的 css 样式为 display:none,但依然会被 JS 代码处理
    解决方式:在滚动函数内添加了条件 if ($('.article-toc').is(':visible')),只有在 toc 可见时才会执行

  实现效果是很满意的,包括点击目录跳转和页面刷新后都会自动展开,也没有多余的动画抖动,甚至优化了一下请求次数,只是这个代码看起来实在是有点惨不忍睹……不过想了想 SE 给每个 HQ 物品都单独做了一张图片,我觉得我这个写法也不是不可原谅,能跑就行.jpg

参考资料


  1. 1. 事前吐槽
  2. 2. 功能设计
    1. 2.1. 需求
    2. 2.2. 思路
  3. 3. 测试
    1. 3.1. 测试用二级标题 1
    2. 3.2. 测试用二级标题 2
  4. 4. 参考资料