vue实现v-html代码块高亮+行号

一、前言

由于最近开发了自己的博客,懂的都懂,既然要写博客,那肯定就得用到文本编辑器,我这里用的是 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 标签;
  • 样式风格似乎是固定,不能选择;
相关推荐
并不会29 分钟前
常见 CSS 选择器用法
前端·css·学习·html·前端开发·css选择器
衣乌安、33 分钟前
【CSS】居中样式
前端·css·css3
兔老大的胡萝卜33 分钟前
ppk谈JavaScript,悟透JavaScript,精通CSS高级Web,JavaScript DOM编程艺术,高性能JavaScript pdf
前端·javascript
低代码布道师35 分钟前
CSS的三个重点
前端·css
耶啵奶膘2 小时前
uniapp-是否删除
linux·前端·uni-app
王哈哈^_^4 小时前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt
cs_dn_Jie4 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic5 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿5 小时前
webWorker基本用法
前端·javascript·vue.js
cy玩具5 小时前
点击评论详情,跳到评论页面,携带对象参数写法:
前端