整个探索的过程断断续续花费了我一些时间,写下这篇文章记录下这个工作的过程,并不复杂,但是有值得以后学习的地方。
问题
maupassant
主题的目录显示在正文中,一旦目录过长就会严重影响正文的排版。
将目录固定在页面上的需求
探索之路 当初选用maupassant
主题就是因为其侧栏特别简约实用,如果在打开文章浏览时将目录也放入侧栏内问题不就解决了吗?于是开始扒主题源码,了解侧栏的机制并开始着手制作目录栏。
注:以下为逐渐探索的过程,若想直接完成我的这个效果,可以直接从第三回开始。
第一回
新建toc.pug
文件在_widgets
文件夹下:
1 2 3 4 5 6 .widget if page.toc .widget-title i(class='fa fa-bars')= ' ' + __('contents') div(id='stoc' class='stoc-article') != toc(page.content, {list_number: theme.toc_number})
之后在主题配置文件_config.yml
中添加侧栏toc
:
1 2 3 4 5 6 7 8 9 widgets: - toc - about - search - category - tag - archivelist - recent_posts - links
在style.scss
中修改基本样式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 .stoc-article { padding : 0.7em 0.7em 0 0 ; } #stoc { line-height : 1em ; .toc { padding : 0 ; margin : 0.5em ; line-height : 1.8em ; li { list-style-type : none; } } .toc-child { margin-left : 1em ; padding-left : 0 ; } }
本地执行hexo server
预览
到这里我以为完结撒花啦🎉,当我发布出去后发现并没有显示出来,之后做了判断验证确实是无法显示,这个问题困扰了我很久,为什么if page.toc
这句判断失败而本地预览却可以呢?侧栏无法识别当前page
吗?
问题搁置了许久,问题没有解决就很闹心,今天在研究博客整体框架时突然想到把目录的配置提前,放到文章生成前的base.pug
文件内,以引入的形式引入到post.pug
能不能成功呢?
第二回
新建base-post.pug
页面(为了避免破坏其他页面的排版),主要代码复制于base.pug
,修改的部分如下:1 2 3 4 5 6 7 8 9 10 11 12 13 14 #layout.pure-g .pure-u-1.pure-u-md-3-4: .content_container block content if page.toc != true .pure-u-1.pure-u-md-1-4: #sidebar each item in theme.widgets != partial('_widget/' + item + '.pug', null, {cache: !config.relative_link}) else .pure-u-1.pure-u-md-1-4: #posttoc i(class='fa fa-bars')= ' TOC ' div(id='stoc' class='stoc-article') != toc(page.content, {list_number: theme.toc_number}) .pure-u-1.pure-u-md-3-4 != partial('_partial/footer.pug')
代码进行前面类似的判断,如果当前文章在front-matter
设置了toc: true
即显示目录,否则显示侧栏。
注:在 post.pug
开头要修改继承的文件为 base-post
。
在style.scss
中修改基本样式
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 #posttoc { position : fixed; margin-top : 25px ; } .stoc-article { padding : 0.7em 0.7em 0 0 ; } #stoc { line-height : 1em ; .toc { padding : 0 ; margin : 0.5em ; line-height : 1.8em ; li { list-style-type : none; } } .toc-child { margin-left : 1em ; padding-left : 0 ; } }
本地预览及推送发布均成功显示,说明这个尝试是可行的,终于算是解决了这个问题:
另外,是否可以把目录伪装成侧栏中的一栏呢?
把代码改成如下即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #layout.pure-g .pure-u-1.pure-u-md-3-4: .content_container block content if page.toc != true .pure-u-1.pure-u-md-1-4: #sidebar each item in theme.widgets != partial('_widget/' + item + '.pug', null, {cache: !config.relative_link}) else .pure-u-1.pure-u-md-1-4: #sidebar #posttoc .widget .widget-title i(class='fa fa-bars')= ' ' + __('contents') div(id='stoc' class='stoc-article') != toc(page.content, {list_number: theme.toc_number}) each item in theme.widgets != partial('_widget/' + item + '.pug', null, {cache: !config.relative_link}) .pure-u-1.pure-u-md-3-4 != partial('_partial/footer.pug')
把目录的样式改成侧栏,然后在目录后面遍历出侧栏其它栏目。
第三回 继续优化第二个问题固定目录栏并优化移动端隐藏目录栏。
在 base-post.pug
中增加移动端判断并修改类名等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #layout.pure-g .pure-u-1.pure-u-md-3-4: .content_container block content if page.toc != true .pure-u-1.pure-u-md-1-4: #sidebar each item in theme.widgets != partial('_widget/' + item + '.pug', null, {cache: !config.relative_link}) else if theme.toc_on_small_screens .pure-u-1.pure-u-md-1-4: #sidebar-toc div(id="sidebar-stoc" class="stoc-article") strong(class="stoc-title") i(class='fa fa-blind')= ' Contents ' div(id="stoc" class='toc-nav') != toc(page.content, {list_number: theme.toc_number}) else .pure-u-1-4.hidden_mid_and_down: #sidebar-toc div(id="sidebar-stoc" class="stoc-article") strong(class="stoc-title") i(class='fa fa-blind')= ' Contents ' div(id="stoc" class='toc-nav') != toc(page.content, {list_number: theme.toc_number}) .pure-u-1.pure-u-md-3-4 != partial('_partial/footer.pug')
修改样式
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 #sidebar-toc { padding-left : 15px ; margin-top : 40px ; padding-bottom : 20px ; word-wrap : break-word; } .stoc-article { position : absolute; padding : 1em 1em 0 1em ; margin-left : 1em ; border-left : rgba(88 ,88 ,88 ,0.1 ) 1px solid; } .stoc-title { font-size : 150% ; } #sidebar-stoc { width : inherit; line-height : 1em ; font-size : 0.9em ; float : left; overflow : auto; } .stoc-fixed { position : fixed; top : 60px ; margin-top : 0 ; max-height : 81% ; overflow : hidden; z-index : 1 ; } .toc-nav { padding : 0.7em 0.7em 0 0 ; } #stoc { line-height : 1em ; .toc { padding : 0 ; margin : 0.5em ; line-height : 1.8em ; li { list-style-type : none; } } .toc-child { margin-left : 1em ; padding-left : 0 ; } }
为了实现固定目录的功能,引入了 toc.js
文件放在source/js
文件夹中,然后注意在 base-post.pug
中 include 该 js 文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 var toc = document .getElementById('sidebar-stoc' )if (toc != null ) { window .addEventListener("scroll" , scrollcatelogHandler); var tocPosition = toc.offsetTop; var height_header = $("#header" ).height(); function scrollcatelogHandler (e ) { var event = e || window .event, target = event.target || event.srcElement; var scrollTop = document .documentElement.scrollTop || document .body.scrollTop; if (scrollTop > tocPosition -60 ) { toc.classList.add("stoc-fixed" ); } else { toc.classList.remove("stoc-fixed" ); } } }
就是现在正在使用的样式啦!
总结 基本实现了预期功能,前后折腾了很长时间,但是这种心想事成的感觉还是很nice的呢!
后面如果有新的bug再慢慢解决吧。
更新2019.2.17 点击无法跳转,我枯了。。。
多方查找原因终于找到了根源,居然是因为aplayer播放器
与toc
不兼容,要是没有看到别人的文章我感觉一辈子都解决不了这个问题 了。
于是把播放器配置设置开关在front-matter
中,在需要使用音乐播放器的页面才设为music: true
,其它用到目录的页面关闭使用。
更新2019.4.3 滚条时对应标题高亮,修改如下:
在toc.js
中增加对每一个标题位置的判断,并为其添加一个class
为active
:
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 var toc = document .getElementById('sidebar-stoc' )var HEADER_OFFSET = 200 ;var toclink = document .getElementsByClassName('toc-link' );var headerlink = document .getElementsByClassName('headerlink' );if (toc != null ) { window .addEventListener("scroll" , scrollcatelogHandler); var tocPosition = toc.offsetTop; function scrollcatelogHandler (e ) { var event = e || window .event, target = event.target || event.srcElement; var scrollTop = document .documentElement.scrollTop || document .body.scrollTop; if (scrollTop > tocPosition -60 ) { toc.classList.add("stoc-fixed" ); } else { toc.classList.remove("stoc-fixed" ); } for (var i=0 ; i<toclink.length; i++){ var currentHeaderTop = headerlink[i].offsetTop - HEADER_OFFSET, nextHeaderTop = i+1 === toclink.length ? Infinity : headerlink[i+1 ].offsetTop - HEADER_OFFSET; if (currentHeaderTop < scrollTop && scrollTop <= nextHeaderTop){ toclink[i].classList.add('active' ); } else { toclink[i].classList.remove('active' ); } } } }
在style.scss
中添加active
类的样式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #stoc { line-height: 1 em; font-weight: 700 ; .active { color: #0085a1; border-radius: 4 px; background-color: #F5F5F5; } .toc { padding: 0 ; margin: 0.5 em; line-height: 1.8 em; li { list-style-type: none; } } .toc-child { margin-left: 1 em; padding-left: 0 ; } }