个性化的内容越来越多,About页面放不下了,于是决定单独写一篇文章记录本博客的配置
主题
NexT.Gemini
不建议用npm安装,因为那样没法魔改。所以一如既往的直接clone就可以了。
背景图片(ribbon)
本来打算上传背景的,但是图片太大了,最后采用了动态生成的ribbon。
在博客的_config.yml,把canvas_ribbon的enable设置成true。
但是原版的ribbon.js有个小问题,就是如果在手机上点击,会连续刷新两次背景。看了一眼代码,问题出在这儿。
1 2 document .onclick = redraw;document .ontouchstart = redraw;
因为不喜欢背景频繁变动,我把这两行给删了,同时也就不能用CDN提供的js文件了。
好在hexo允许自行配置vendors。在next的_config.yml里头找到vendors
项目,然后加入下面内容(注意改成自己的js文件路径)
1 2 # 这里js文件被我放在 next\source\js\ribbon.min.js canvas_ribbon: /js/ribbon.min.js
显示hexo和next版本号
页脚显示版本号这个特性在v7的next主题是有的,但是v8给去掉了。我个人比较喜欢这个特性,于是琢磨了半天nunjucks,把显示版本号给魔改回来了。
在footer.njk中把对应内容替换成下面这些~
1 2 3 4 5 6 7 8 9 10 11 12 13 {%- if theme.footer.powered %} <div class ="powered -info "> <span class ="post -meta -item "> {{- __ ('footer.powered' , next_url ('https://hexo.io' , 'Hexo' , {class : 'theme-link' }) + ' v' + hexo_version) }} </span> <span class ="post -meta -item "> {%- set next_site = 'https://theme-next.js.org' if theme.scheme === 'Gemini' else 'https://theme-next.js.org/' + theme.scheme | lower + '/' %} {{- __ (' 主题 – ' + next_url (next_site, 'NexT.' + theme.scheme, {class : 'theme-link' }) + ' v' + next_version) }} </span> </div> {%- endif %}
然后在locals.js替换下面内容
1 2 3 4 5 6 7 const { version, config } = hexo;locals.hexo_version = version;
版权信息和字数统计并排
这个也是v7的next主题有的特性,升级到v8又给改没了。。。
这个改起来就很简单了,无非就是把字数统计的span放到版权信息的div里头,如下所示。
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 <div class ="copyright "> {%- set copyright_year = date (null , 'YYYY' ) %} © {% if theme.footer.since and theme.footer.since != copyright_year %}{{ theme.footer.since }} – {% endif %} <span itemprop="copyrightYear" >{{ copyright_year }}</span> <span class ="with -love "> <i class =" {{ theme.footer.icon.name }}"></i> </span> <span class=" author" itemprop=" copyrightHolder">{{ theme.footer.copyright or author }}</span> {%- if config.symbols_count_time.total_symbols or config.symbols_count_time.total_time %} {%- if config.symbols_count_time.total_symbols %} <span class=" post-meta-item"> <span class=" post-meta-item-icon"> <i class=" fa fa-chart-line"></i> </span> {%- if theme.symbols_count_time.item_text_total %} <span>{{ __('symbols_count_time.count_total') + __('symbol.colon') }}</span> {%- endif %} <span title=" {{ __ ('symbols_count_time.count_total' ) }}">{{ symbolsCountTotal(site) }}</span> </span> {%- endif %} {%- if config.symbols_count_time.total_time %} <span class=" post-meta-item"> <span class=" post-meta-item-icon"> <i class=" fa fa-coffee"></i> </span> {%- if theme.symbols_count_time.item_text_total %} <span>{{ __('symbols_count_time.time_total') }} ≈</span> {%- endif %} <span title=" {{ __ ('symbols_count_time.time_total' ) }}">{{ symbolsTimeTotal(site, config.symbols_count_time.awl, config.symbols_count_time.wpm, __('symbols_count_time.time_minutes')) }}</span> </span> {%- endif %} {%- endif %} </div>
页面载入动画速度
v7的主题也没这个问题,升级到v8之后,首页加载文章的动画速度慢的令人抓狂。在打了不少断点之后,终于搞清楚next主题是如何控制动画速度的了。
hexo的动画是由motion.js进行组装,然后交给anime.js(CDN提供)执行。其中anime.js里头有个参数叫duration,默认值是200,作用是控制动画执行的时间(也就是速度)。这个默认值是在博客的motion.js里头设定的,如下所示。
1 2 3 4 const timeline = window .anime .timeline ({ duration : 200 , easing : 'linear' });
motion.js里头还有个参数叫deltaT,作用是在默认时间基础上进行偏移,如下所示。
1 2 3 4 sequence.forEach (item => { if (item.deltaT ) timeline.add (item, item.deltaT ); else timeline.add (item); });
那么要改变动画速度,直接修改对应的deltaT就可以了,这里拿文章载入动画速度为例。这里自带的deltaT是-=100
,那么duration算出来是100
,所以才感觉拖泥带水。最后我改成了-=200
,此时duration是0
,然后动画就变得干脆利索了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 postList : function ( ) { const sequence = []; const { post_block, post_header, post_body, coll_header } = CONFIG .motion .transition ; function animate (animation, selector ) { if (!animation) return ; document .querySelectorAll (selector).forEach (targets => { sequence.push ({ targets, complete : () => targets.classList .add ('animated' , animation), deltaT : '-=200' }); }); } animate (post_block, '.post-block, .pagination, .comments' ); animate (coll_header, '.collection-header' ); animate (post_header, '.post-header' ); animate (post_body, '.post-body' ); return sequence; }
字数统计和阅读时长
hexo-word-counter
版本:v0.1.0
代码块不计入字数(exclude_codeblock: true)
注意:安装完之后一定要执行hexo clean
!
阅读进度条
next主题的_config.yml里找到Reading progress bar开启
首页隐藏分类(比如公告)
hexo-generator-index2
禁用更新日期
next主题的_config.yml > post_meta > updated_at > enable: false
全英语链接
全英语链接方便搜索引擎收录,这里简单修改hexo站点的_config.yml
即可,下面给出本博客的配置
我的.md
文件名都是英语,所以URL > permalink可以设置为:category/:title.html
文章的类别大多都是中文名,可以通过Category & Tag > category_map进行映射
1 2 3 4 5 6 :category/:title.html category_map: 技术: tech
图片相关
图床(GitHub)
图床我直接使用的 GitHub,新建一个 repo,然后开启 GitHub Page(Settings > Pages)。Branch 选择 main,path 选择 root(根目录)。
然后就可以通过下面方式访问图片了。
1 2 # 假设图片放在 repo 的 img 文件夹里 ![](https://{你的博客域名}/{图床repo名称}/img/{你的图片})
图片延迟加载(lazyload)
lazyload就是延迟加载,只有在看到图片的时候才加载,从而加快网页载入速度。
next主题的_config.yml,把lazyload设置成true
但是有些图片我又不希望延迟加载(比如 about 页面的 osu_stats),所以对post.js
进行修改
注意的是,这里加入了加载中的占位图,就顺带修复了原有的TOS跳转问题。
1 2 3 4 5 6 7 8 9 10 const placeholderUrl = "https://oscarcx.com/hexo_resource/img/loading_cow.png" ; if (theme.lazyload ) { if (data.content .indexOf (theme.lazyload_exclude ) == -1 ) { data.content = data.content .replace (/(<img[^>]*) src=/img , `$1 src="${placeholderUrl} " data-src=` ); } }
然后在 next 主题的 _config.yml 增加lazyload_exclude
,写上不希望延迟加载的图片 src 即可(src 的任何一部分都行)
1 2 3 4 lazyload: true lazyload_exclude: osu-sig
图片缩放(mediumzoom)
mediumzoom是一个点击放大图片的插件,挺实用的。
next主题的_config.yml,把mediumzoom设置成true
黑幕(spoiler)
文字模糊处理,点击可见(比如练习题答案)
插件项目地址:unnamed42/hexo-spoiler
安装:npm install hexo-spoiler --save
(在博客根目录使用)
使用方式如下所示
1 2 {% spoiler text %} {% spoiler option:value text... %}
渲染引擎(renderer)
把 hexo 自带的 hexo-renderer-marked 卸载了,现在使用的是 hexo-renderer-markdown-it-plus
配置如下所示:
1 2 3 markdown_it_plus: typographer: false quotes: “”‘’
typographer 这个功能是默认开启的,会在渲染过程中,自动把所有的英语引号全部换成中文引号。具体解释可以看 6.4.0版本之后的两个问题 。
可以把下面两行复制到文章中进行测试,如果左右渲染出来一样,就是被自动替换了。
'(U+0027) ---> ’(U+2019)
"(U+0022) ---> “(U+201C) + ”(U+201D)
所以只需要 typographer: false 就能禁用这个坑爹的功能
公式显示
直接使用 katex,体积小,而且支持公式的自适应换行,安装方法见这篇官方教程:Math Equations | NexT 。
hexo 自带的renderer 不支持 katex,所以我安装的是升级版 hexo-renderer-markdown-it-plus 。
折叠块
本来想自己手搓一个的,发现有人已经写过,效果还不错,就不重复造轮子啦
插件:hexo-content-blocks
需要修改主题的head.njk
,然后在 hexo 博客的 config.yml
增加配置项目,具体看插件 repo 的 README 文件。
效果如下:
我是折叠块
效果还不错吧~
移动端可折叠目录
移动端显示目录是通过修改css实现,css相关改动全部统一放在 source\_data\styles.styl
目录的折叠需要使用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 44 45 46 47 48 49 50 51 52 53 54 # 路径:themes\next\layout\_layout.njk # 在 {{- next_inject('bodyEnd') }} 上方插入这些内容 <script type ="text/javascript" > function collapsableTitle (x ) { var nav = document .getElementsByClassName ("sidebar-nav-toc" )[0 ]; if (x.matches ) { var content = document .getElementsByClassName ("sidebar-panel-container" )[0 ]; if (content.style .display = "none" ) { nav.textContent = "文章目录 [展开]" ; } else { nav.textContent = "文章目录 [折叠]" ; } } else { nav.textContent = "文章目录" ; } } var x = window .matchMedia ("(max-width: 991px)" ); collapsableTitle (x);x.addListener (collapsableTitle); var tos = document .getElementsByClassName ("sidebar-nav" )[0 ];var i;tos.addEventListener ("click" , function ( ) { this .classList .toggle ("active" ); var content = document .getElementsByClassName ("sidebar-panel-container" )[0 ]; var nav = document .getElementsByClassName ("sidebar-nav-toc" )[0 ]; if (content.style .display === "block" && window .innerWidth < 991 ) { content.style .display = "none" ; nav.textContent = "文章目录 [展开]" ; } else { content.style .display = "block" ; if (window .innerWidth < 991 ) { nav.textContent = "文章目录 [折叠]" ; } } }); document .addEventListener ('pjax:complete' , function ( ) { if (window .innerWidth < 991 ) { let content = document .getElementsByClassName ("sidebar-panel-container" )[0 ]; content.style .display = "none" ; let nav = document .getElementsByClassName ("sidebar-nav-toc" )[0 ]; nav.textContent = "文章目录 [展开]" ; } }); </script >
已知问题(不修复):在桌面版阅读文章时,点击“站点概览”,然后拖拽浏览器进入移动端,不显示目录
参考:How To Create a Collapsible - W3Schools
其它改动
微调行距,字体大小等,并且在移动端也显示目录
全部统一放在 source\_data\styles.styl
然后把next主题的_config.yml
的这部分取消注释就可以了。写在这个文件里的css会被添加到末尾,所以可以直接覆盖默认样式。
1 2 3 4 5 # Define custom file paths. # Create your custom files in site directory `source/_data` and uncomment needed files below. custom_file_path: (省略若干) style: source/_data/styles.styl
废弃的魔改
音乐播放器
注:播放器感觉没啥用,已经被我移除
APlayer
版本:v1.10.1
安装方法:把该项目的dist文件夹复制到themes\next\source
页面跳转不打断播放:在主题的_config.yml,把pjax设置成true
要让播放器生效,需要修改_layout.njk
1 2 3 4 5 6 7 # 路径:themes\next\layout\_layout.njk # 在<div class ="headband" > </div > 下方插入这些内容 <link rel ="stylesheet" href ="/aplayer/APlayer.min.css" > <div id ="aplayer" > </div > <script type ="text/javascript" src ="/aplayer/APlayer.min.js" > </script > <script type ="text/javascript" src ="/aplayer/music.js" > </script >
使用csv文件来管理曲库,配合Python脚本自动生成music.js
配置
大部分配置项都可以在Aplayer文档 找到,这里仅列出我改过的配置。
fixed(吸底模式): true
preload(预加载): 'metadata'
autoplay(自动播放): false
order(播放顺序): 'random'
注意:预加载默认是开启的。反正大部分人也不会点播放器,所以只加载metadata就能有效地节约流量。
自动生成music.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 import csvimport jsonfilename = 'musicDB.csv' repo_url = 'https://oscarcx.com/hexo_resource/music/' with open (filename, encoding='UTF-8' ) as f: reader = csv.reader(f) music_list = list (reader)[1 :] result = [] for i in range (len (music_list)): data = {} data['name' ] = music_list[i][0 ] data['artist' ] = music_list[i][1 ] mp3_file_name = music_list[i][2 ] if music_list[i][2 ] else music_list[i][0 ] data['url' ] = repo_url + 'song/' + mp3_file_name + '.mp3' cover_name = music_list[i][3 ] if music_list[i][3 ] else music_list[i][0 ] data['cover' ] = repo_url + 'cover/' + cover_name + '.jpg' result.append(data) with open ('music.js' , 'w' , encoding='UTF-8' ) as f: f.writelines([ "const ap = new APlayer({" + "\n" , " container: document.getElementById('aplayer')," + "\n" , " fixed: true," + "\n" , " preload: 'metadata'," + "\n" , " autoplay: false," + "\n" , " order: 'random'," + "\n" , " audio: " , ]) json.dump(result, f, ensure_ascii=False , sort_keys=False , indent=4 ) f.write("});" )
mathjax 长公式
在 next 主题的 _config.yml,可以开启 mathjax(enable: true)
但是,mathjax 长公式在文章中会超出范围,溢出页面。这个问题在移动端上(因为屏幕窄)特别严重。
这篇博客(Hexo+NexT使用MathJax问题 )给了我启发。仔细观察可以得知,在 li 元素中的 mathjax 公式并不会溢出,在公式超出区域时会在底部生成滚动条,关键就在于has-jax
这个 class。
在 math.styl 中,可以发现下面内容
1 2 3 4 .has-jax { overflow : auto hidden; }
所以需要在 mathjax.js 中进行如下修改,增加一个 target 是否为 p 元素的判断,这样单行的公式在超出区域时也有滚动条了
1 2 3 4 5 6 7 8 9 document .querySelectorAll ('mjx-container' ).forEach (node => { const target = node.parentNode ; if (target.nodeName .toLowerCase () === 'li' ) { target.parentNode .classList .add ('has-jax' ); } else if (target.nodeName .toLowerCase () === 'p' ) { target.classList .add ('has-jax' ); } });