前言
我的博客主题采用的是black-blue,从SPFK和yalia主题摇身一变过来的,整体风格偏黑,我比较喜欢,最重要的是,手机版有目录页面!!!
然而最近在使用的过程中,发现代码块的效果有很多问题
- 代码块的标题栏长度,随着滚动会不及代码的长度
- 代码块标题栏没有当前语言的显示
- 代码块不支持VEX等大部分的CG语言
代码块滚动问题
滚动条的问题原本不难解决,只要让它窗口监听resize事件,当窗口发生变化的时候,让代码的长度匹配标题的长度。
然而这里并没有这么简单,最主要的问题是,标题栏居然是个CSS伪元素,正如上面截图看到的,它的element是::before,那么要对其进行DOM操作就变得非常曲折。
后面我上网查了之后,得出结论就是要动态加入style标签修改::before的样式。
虽然思路是对的,但是代码块的::before都是源于同一个CSS,直接修改就会修改全部的代码块,最后只能让一个代码块适配。
因此我要为一个代码块另外创建一个有区分的CSS样式表。
这个过程我一度怀疑这样的可行性,如此麻烦还不如用div进行操作。
后来还是让我找到了解决方案,将下面的代码放到article.ejs里面(这个文件在主题文件夹的layout里面)
这样在生成文章html的时候,代码就会嵌套到文章当中。
1 | //添加到article.ejs中 |
代码块标题栏没有当前语言的显示
在上面的截图可以看到伪元素的content上是有attr(data-lang)属性。
网上查了才知道原来这个可以获取html的自定义属性嵌入到内容中,显然这里的html就没有这个属性。
但是代码块是在哪里生成的,又应该在哪里嵌入这个html属性呢?
经过我一番摸索,在article.ejs里面发现了猫腻,
上面的div标签是通过浏览器的控制台发现的,但是文章内容这么多,为何ejs的模板却这么短。
原来所有的内容都在post.content里面了。
也就是说hexo内部完成了markdown的解析,作为hexo的使用者只需要关心网站的架构即可。
但是这样就导致我没有办法给相应的代码块添加对应语言的标签了。(或许可以通过jquery添加对应的data-lang属性,但是获取到对的应语言似乎挺麻烦的)
鉴于此,我就在hexo里面寻找答案,况且后面解决代码高亮的问题也许好在hexo的内核里面寻求答案。
经过很长时间的摸索,我终于找到了关键代码。在node_module中的hexo\lib\plugins\filter\before_post_render文件其中有backtick_code_block.js的js文件。
这个文件就是hexo解析markdown代码块的核心代码,通过在这里加入console.log之后可以在hexo生成文章链接的时候看到信息反馈在git中,
这里通过正则表达式将代码块识别出来,并且分别截获代码块后面的内容,进行不同的操作。而关键的代码语言存储到options.lang中,最后options传入到highlight函数中。
在node_module的hexo-util\lib中可以找到highlight.js,这里就可以找到html代码块的生成代码了。
在这里加入data-lang就可以在生成代码块的时候将语言的信息嵌套到html供::before去调用了。
加入自定义语言高亮支持
通过上面的一通操作可以知道,hexo解析markdown代码块是通过highlight.js来实现的。上面hexo的highlight.js是hexo内部用来调用外部的highlight.js用的,在node_module文件夹中就有highlight.js,专门用来高亮代码的脚本。
奈何特效相关的编程语言比较小众,它居然还支持MEL,我都惊了。然而VEX还是个遗憾,另外之前我写了正则表达式相关的博文,正则表达式也没有高亮支持。
既然没有那就做一个呗,反正它内部有那么多门语言作为参考我就不信自己搞不定,所以我先从简单的正则表达式入手。
不过加入之前要先在hexo弄好相关的代码,否则就会跳过脚本的。
首先是node_modules\highlight.js\lib 的 index.js,需要在里面添加新的注册语言。
另外node_modules\hexo-util 的 highlight_alias.json可以添加语言的模糊识别。
后面就是如何对相应的内容进行高亮显示。
1 | module.exports = function(hljs) { |
从上面的代码可以知道,highlight.js是通过正则表达式找到相应的代码加入class名,而着色是需要自己写css给相应的代码进行着色。
1 | (<script>(.*\n)+</.*?>)|(<.*?>)(?=(.*\n)+ |
貌似正则表达式还是比较简单的,要处理Vex这种复杂的语言要如何进行正则表达式判断呢?
其实没有那么复杂,因为VScode和sublime都支持VEX高亮,截取里面的关键代码就好了。
VEX高亮脚本-链接
当然别忘了加入CSS样式处理高亮效果
1 | pre .vex_built_in{color:#66cccc} |
Vex代码的呈现效果:
1 | for (int i = 0; i < @numprim; i++) |