一、前言
由于最近开发了自己的博客,懂的都懂,既然要写博客,那肯定就得用到文本编辑器,我这里用的是 vue-quill-editor。具体怎么用百度都有的,就不多说了。
通过编辑器编辑的文章发布以后,发现样式实在是太丑了,对于我这种只看颜值的人,实在是不能忍。
这里主要针对代码块做一个代码高亮及添加行号的样式优化。
网上查了一些资料,发现有2种插件可用(highlight.js 和 prismjs)。
二、依赖
- vue 2.x
- element ui
- vue-quill-editor
- highlight.js
- highlightjs-line-numbers.js
- prismjs
- babel-plugin-prismjs
三、实现
3.1、highlight 代码高亮+行号
3.1.1、安装
less
// 代码高亮
npm i highlight.js
// 行号
npm i highlightjs-line-numbers.js
3.1.2、创建 highlightjs-line-numbers.js
由于引用 highlightjs-line-numbers.js 源码,会报错:highlight.js not detected!
所以我这里手动改一下该源码,在项目目录下创建一个文件夹 resources,在该文件夹下创建文件 highlightjs-line-numbers.js,将 highlightjs-line-numbers.js 源码拷贝进去,并做一些修改,需要修改的代码如下:
scss
// jshint multistr:true
function lineNumberInit(hljs, w, d) {
.......
if (hljs) {
hljs.initLineNumbersOnLoad = initLineNumbersOnLoad
hljs.lineNumbersBlock = lineNumbersBlock
hljs.lineNumbersValue = lineNumbersValue
addStyles()
} else {
w.console.error('highlight.js not detected!')
}
.......
}
export { lineNumberInit }
3.1.3、创建自定义指令
我这里选择使用 vue 自定义指令的方式来实现,在项目 utils 目录下创建 highLight.js 文件,内容如下:
javascript
import Vue from 'vue'
// 引入依赖
import hljs from 'highlight.js'
import 'highlight.js/styles/atom-one-dark.css' // 代码高亮的样式
import { lineNumberInit } from '../resources/highlightjs-line-numbers.js' // 行号
lineNumberInit(hljs, window, window.document)
// 创建vue自定义指令
Vue.directive('highlight', el => {
const blocks = el.querySelectorAll('pre')
blocks.forEach(block => {
hljs.highlightBlock(block)
hljs.lineNumbersBlock(block)
})
})
3.1.4、注册自定义指令
main.js 中注册自定义指令,代码如下:
arduino
import '@/utils/highLight.js'
3.1.5、使用自定义指令
给渲染内容的标签添加该自定义指令即可。
ini
<div v-highlight ref="blogContentRef" v-html="blogInfo.content"></div>
3.1.6、效果展示
3.1.7、存在问题
不知道什么原因,如果文章添加了目录功能或图片预览功能后,当点击目录或者预览图片后,代码块的行号格式会消失,体验特别不好。
3.2、prismjs 代码高亮+行号
3.2.1、安装
less
// 安装 prismjs
npm i prismjs
// 安装 prismjs 的编译器插件
npm i babel-plugin-prismjs -D
3.2.2、配置 prismjs
在项目下找到 babel.config.js,在 module.exports 下的 plugins 中追加以下配置,如果没有则手动添加。
arduino
plugins: [
[
"prismjs",
{
languages: ["javascript", "css", "markup"],
plugins: ["line-numbers"], // 配置显示行号插件
theme: "okaidia", // 主题名称
css: true,
},
],
],
3.2.3、创建自定义指令
我这里也选择使用 vue 自定义指令的方式来实现,在项目 utils 目录下创建 highLight.js 文件,在该文件中引入 prismjs 插件并创建 Highlight 自定义指令,内容如下:
javascript
// 引入 prismjs 插件
import Prism from 'prismjs'
// 创建指令 v-highlight
const Highlight = {}
Highlight.install = Vue => {
Vue.directive('highlight', {
// 指令所在组件的 VNode 及其子 VNode 全部更新后调用
componentUpdated: () => {
// 代码美化
Prism.highlightAll()
}
})
}
export default Highlight
3.2.4、注册自定义指令
在 main.js 中注册自定义指令,代码如下:
javascript
import Highlight from '@/utils/highLight.js'
Vue.use(Highlight)
3.2.5、使用自定义指令
给渲染内容的标签添加该自定义指令即可。
ini
<div v-highlight ref="blogContentRef" v-html="blogInfo.content"></div>
3.2.6、注意(重点)
如果你已经按以上步骤做了,但是你发现代码块并没有任何变化。其实这里重点需要注意的一个问题是:
通过文本编辑器编辑的代码块,在页面上通过 v-html 指令渲染出来后,你会发现只有 pre 标签,里面并没有 code 标签。
而这个插件只对 pre 标签嵌套的 code 标签起作用,插件规定有的类名必须写在 code 标签上,比如设置行号的类名:line-numbers 和设置编程语言的类名:language-js,所以没效果是正常的。
那么知道问题所在,我们就可以对文章内容做一个处理,那就是在文章内容存入数据库前,做一个全局替换工作,手动将 code 标签和一些必要的类名加进去。
以我的代码为例:
this.blogForm.content 为原本的内容
newContent 为全局替换后的内容
xml
let newContent = this.blogForm.content.replace(/<pre class="ql-syntax" spellcheck="false">/g, '<pre class="ql-syntax line-numbers language-js" spellcheck="false"><code class="language-js">')
newContent = newContent.replace(/</pre>/g, '</code></pre>')
3.2.7、效果展示
再次刷新页面,代码块样式生效了,效果如下:
四、总结
以上就是代码块高亮+行号的两种实现方式,我个人比较喜欢 prismjs,因为没有什么 bug,不影响体验。对于这两种插件,对比如下:
highligh 优势:
- highligh 不需要对博客内容进行全局替换增加 code 标签;
- highligh 代码高亮样式可选择比较多。
highligh 劣势:
- highlightjs-line-numbers.js 源码有问题;
- 代码块的行号格式会有消失的情况;
prismjs 优势:
- 没有什么bug,代码块的行号格式不会莫名消失;
- 添加行号使用 line-numbers 类名即可。
prismjs 劣势:
- 需要手动添加 code 标签;
- 样式风格似乎是固定,不能选择;