前端显示代码高亮
Time:2021-3-22
前言
搭建博客网站的过程还真是多bug…什么奇奇怪怪的问题都有,很大原因就是这个VueCLI版本太高级了…都没什么关于这个版本的使用的资料,中文的官方文档简单的就好像什么都没说,基本的vue语法就那样,但是工程的结构和一些关键API却没有详细说明,难受。使得我总是只能自己不断揣测和尝试。这个代码高亮也是,搞了两天,终于才觉悟问题何在。
转载请注明出处!!!
Author:雾雨霜星
欢迎来我的个人网站进行学习:
https://www.shuangxing.top/#/passage?id=16
highlight.js
这是前段最多人使用的代码高亮的依赖了,确切来说他仅仅是一个js文件,里面封装了可以处理代码高亮的函数,主要有:
-
highlightBlock(block):
-
说明:对包含代码的 DOM 节点添加高亮标记。默认使用语言检测,但是你也可以在节点上添加 class 属性来指定语言。
-
参数:block是DOM节点
-
-
initHighlighting():
- 说明:为页面中所有
<pre><code>..</code></pre>
块添加高亮标记。配合 styles 中的 css 使用即可实现着色。
- 说明:为页面中所有
-
highlightAll():
- 说明:自动处理整个页面所有的
<pre><code>..</code></pre>
部分,进行代码高亮,感觉效果与前者一样。
- 说明:自动处理整个页面所有的
在网上,目前大部分使用highlight的思路是:
- 使用npm安装引入
- 定义全局指令 v-highlight
- 全局指令中通过找到
<pre><code>..</code></pre>
调用highlightBlock(block)函数进行处理
可以说这是使用highlight最好的思路,因为在vue路由切换后即使是异步请求的数据仍然可以使用vue指令使得代码高亮生效。
但是他们的方法里面有个问题,就是使用了Vue.use,这是VueCLI3以前常见的方法,但是在VueCLI4.5中如果这样做,会报错,或者发现指令没有效果。解决办法如下详述,
VueCLI4.5中Vue实例的建立
因为在VueCLI4.5中是隐式建立App实例,在main.js可以看到:
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
createApp(App).use(router).mount('#app')
根本没有Vue实例直接给出,直接import Vue from ‘vue‘?不行的,指令不会有效果的。
所以就要聪明点,改写为显式的,但是直接按照VueCLI2的写法,会报错。
我就试着这样写,定义常量作为这个createApp的API输出:
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(router)
app.mount('#app')
经过测试,这样写没有任何问题。
在这里,原本常写的Vue实例Vue,其实只是换了个名字叫app而已。同样都是以App作为组件来建立的。
highlight实现
那么就直接记录关于如何使用highlight.js来实现代码高亮吧。
参考:
- https://blog.csdn.net/qq_43332570/article/details/107079382
- https://www.jianshu.com/p/6c1e4fcc6d6f
- https://blog.csdn.net/Cribug8080/article/details/101370107
-
安装引入:
使用npm进行安装,在终端输入:
npm install highlight.js --save-dev
或者VueCLI3以上可以进入Vue ui中,在依赖项选择添加依赖,查找后进行安装即可。
-
配置全局指令:
主要是在main.js中,在进行实例初始化之前进行配置。
如果是VueCLI2的工程,如下:
import Vue from 'vue' import App from './App' import router from './router' import hljs from 'highlight.js' import 'highlight.js/styles/dracula.css' Vue.config.productionTip = false // 定义一个全局指令 Vue.directive('highlight',function (el) { let blocks = el.querySelectorAll('pre code'); blocks.forEach((block)=>{ hljs.highlightBlock(block) }) }) new Vue({ el: '#app', router, render: h => h(App) })
注意要import得到’highlight.js’和相应的代码高亮风格的css文件。
对于VueCLI4.5的如下:
import { createApp } from 'vue' import App from './App.vue' import router from './router' import hljs from "highlight.js" import 'highlight.js/styles/github-gist.css' /*createApp(App).use(router).mount('#app')*/ const app = createApp(App) app.use(router) app.mount('#app') // 定义一个全局指令 v-highlight:用于显示代码高亮 app.directive('highlight',function (el) { let blocks = el.querySelectorAll('pre code'); blocks.forEach((block)=>{ hljs.highlightBlock(block) }) })
我这里之所以使用el.querySelectorAll(‘pre code’);是因为在Typora得到的markdown文件,里面代码部分都是这个格式的,所以我就对这部分进行代码高亮。
-
使用指令:
如果是对html内容进行代码高亮,就使用过刚才定义的指令,对相应div进行使用即可,例如:
<template> <div> <div id="passage-main-area" v-html="passage_article" v-highlight></div> </div> </template>
如果只是普通的
<pre><code>..</code></pre>
部分,即不在html中,那么直接在相应组件内import得到highlight.js然后在mounted生命周期函数中调用highlight.js的highlightAll()函数即可,如果是在路由,那么应该还需要调用initHighlighting()函数,最好全都调用吧。<template> <div> <pre><code>xxxx</code></pre> </div> </template> ... ... <script> import hljs from 'highlight.js' ... ... mounted() { hljs.highlightAll(); hljs.initHighlighting(); } } </script> ... ...
注意记得style中还需要通过@import引入highlight.js/style中的样式才能有效果。
小插曲
我已经不记得自己试了多少方法了。
一开始要用指令进行实现的时候,就已经折腾了无数次了,后来看到一个把highlight.js插件化调用的方法,即写了一个js用于进行自定义指令声明,然后export出去给Vue实例use,可惜我当时,想到了改写那个createApp的API生成实例的方法,用了app.use也还是没有成功,因为在那里面进行指令声明是Vue.directive,但是其实根本没有Vue这个名字的实例,只是import Vue from ’vue‘是没有真的实例的。
按照在组件中import引入highlight.js和相应的css文件,然后直接在mounted钩子中使用那两个全局的代码高亮函数,可以实现普通的pre和code组合元素内代码高亮,但是通过我axios从后端请求得到的html,这样就没有效果,指令也不生效。
还试过,企图通过DOM操作获取div中的pre和code,然后直接在生命周期函数中调用highlightBlock(block)函数进行处理,但是,搞了一个早上也还是没能够成功得到这个子节点,我都想要不要对子节点列表循环比较进行获取了。
然后我吃了个饭,回来后直接觉悟,是我的Vue实例名字的问题!试试改写!才成功实现了通过指令进行代码高亮。
转载请注明出处!!!
Author:雾雨霜星
欢迎来我的个人网站进行学习:
https://www.shuangxing.top/#/passage?id=16
PS: 毕竟,霜星酱水平有限,如果发现任何错误还请及时邮箱告知我,我会去改哦!