使用Prismjs让你写的代码高亮起来(以Vue3为例)

tinycme编辑器

tinymce编辑器界面

【tips】:tinymce是国外的一个功能超全开箱即用的富文本编辑器,他是一个开源的编辑器,除了基本的功能外还可以通过插件的形式拓展,插件也只需要简单的添加插件名称即可,插件分为开源插件和高级插件,其中高级插件功能需要付费,但开源的功能完全够用,而且提供了多种主题选择,还可以高度自定义编辑器样式,可以在 Vue、React、Angular、Blazor、Svelte、Node+Express等多种环境中使用。

目录

1.前台展示tinymce编辑器编辑的内容时踩的坑

2.安装PrimsJS代码高亮库

3.解决PrimsJS添加后代码不高亮的问题

4.给代码块添加行号

5.PrimsJS代码高亮的原理

一、前台展示tinymce编辑器编辑的内容时踩的坑

最近做了一个小项目,该项目主要是将tinymce富文本编辑器编辑的内容在前台展示,我很简单的以为只需要用Vue的v-html解析就能正常展示了,像下面这样

<template>
    <div class="article-wrapper">
        <template v-for="item in articleInfoData">
            <h2 class="title">{{ item.title }}</h2>
            <p class="desc" v-if="item.desc">摘要:{{ item.desc }}</p>
            <div class="content" v-html="item.content"></div>
            <p class="date">{{ item.created_at }}</p>
        </template>
    </div>
</template>

然而并没有那么简单,纯文本编辑的内容可以正常渲染,但是代码块就是显示纯文本,代码没有高亮,就像下面这样

图片

这并非是我们所期待的,我们所期待的应该是下面这样的,让不同代码更加突出展示

图片

后来才发现代码高亮是需要像prismjs这样的库来进行解析的,我们审查tinymce编辑器的代码块元素后会发现,pre->code标签下他给代码块添加了好多标签及样式,但是

图片

我们获取到编辑器提交给后台的数据却发现pre->code标签下就只有我们插入的代码块,就像下面这样,

图片

起初我还以是tinymce编辑器配置的问题,导致缺失了pre->code标签下面的标签及样式,后来看完了tinymce官方文档的配置也没有找到类似的配置。

二、安装Prismjs代码高亮库

后来在网上找到了代码高亮库prismjs并愉快的添加到了Vue3+Ts项目中

什么是prismjs

图片

官方是这样描述的,他是一个非常简单快速可拓展且支持超多语言的轻量级代码高亮库。官网地址

//安装
npm install prismjs

//引入Prism(我们只需要在局部引入即可,我这里是在文章内容展示组件中引入)
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import type { Ref } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { api } from "@/assets/config/api"
import { request } from "@/assets/common/request"
import Prism from "prismjs"//导入代码高亮插件的core(里面提供了其他官方插件及代码高亮样式主题,你只需要引入即可)
import "prismjs/themes/prism-tomorrow.min.css"//引入代码高亮主题(这个去node_modules的安装prismjs中找到想使用的主题即可)

const router = useRouter()
const route = useRoute()
const articleInfoData: Ref<Array<object>> = ref([]);

onMounted(() => {
    getArticleInfo()
    Prism.highlightAll()// 全局代码高亮
})
function getArticleInfo(): void {//从后台请求数据
        request.get(api.GetArticleInfo, {
            id: route.params.id
        }).then(res => {
          articleInfoData.value = res?.data?.data
        }).catch(err => {
           console.log(err)
        })
    })

}
</script>

但结果又出现了下面的这种问题,明显可以看到prismjs以及css是被加载了的,但代码还是没有被高亮

图片

后来研究才发现是因为prismjs执行的时机不对导致pre->code中的代码没有被prismjs解析添加相应的标签。

三、解决PrimsJS添加后代码不高亮的问题

解决办法也很简单,我们可以给Prismjs高亮方法添加一个定时器延迟加载,或者使用

onMounted(() => {
    getArticleInfo()
     setTimeout(() => {
        Prism.highlightAll()// 全局代码高亮
    }, 100)
})

async/await配合Promise进行加载,等数据完全加载完后再用Prismjs进行解析即可实现代码高亮,就像下面那样(需要注意的是一定要等v-html中后台返回的数据加载完毕后才可以被Prismjs解析)

<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import type { Ref } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { api } from "@/assets/config/api"
import { request } from "@/assets/common/request"
import Prism from "prismjs"//代码高亮插件的core
import "prismjs/themes/prism-tomorrow.min.css"//高亮主题
const router = useRouter()
const route = useRoute()
const articleInfoData: Ref<Array<object>> = ref([]);
onMounted(async () => {
    await getArticleInfo().then(res => {
        articleInfoData.value = res
    }).catch(err => {
        console.log(err);
    })
     Prism.highlightAll()// 全局代码高亮(必须等获取数据之后,代码高亮才能生效,也可以用定时器定时)
})
function getArticleInfo(): Promise<Array<object>> {//从后台请求数据
    return new Promise((resolve, reject) => {
        request.get(api.GetArticleInfo, {
            id: route.params.id
        }).then(res => {
            resolve(res?.data?.data)
        }).catch(err => {
            reject(err)
        })
    })
}
</script>

图片

四、给代码块添加行号

我们从上图中可以发现虽然我们完美的给代码添加理论高亮,但我们在vscode中使用时会发现,每行代码都有相应大行号,这样代码出错时我们可以直接定位到某一行。

我们可以看到Prism官方 https://prismjs.com/index.html#plugins 提供了一些常用的插件,我们选择红框中的行号

图片

那么如何使用行号插件呢?其实很简单,我们刚刚在上文中安装了Prism,只需要在node_modules中找到刚刚安装的prismjs中的plugins,然后找到对应的插件引入即可。

图片

在项目中需要这样引入

<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import type { Ref } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { api } from "@/assets/config/api"
import { request } from "@/assets/common/request"
import Prism from "prismjs"//代码高亮core
import "prismjs/plugins/line-numbers/prism-line-numbers.min.js"//行号插件
import "prismjs/themes/prism-tomorrow.min.css"//高亮主题
import "prismjs/plugins/line-numbers/prism-line-numbers.min.css"//行号插件的样式
const router = useRouter()
const route = useRoute()
const articleInfoData: Ref<Array<object>> = ref([]);
onMounted(async () => {
    await getArticleInfo().then(res => {
        articleInfoData.value = res
    }).catch(err => {
        console.log(err);
    })
    Prism.highlightAll()// 全局代码高亮(必须等获取数据之后,代码高亮才能生效,也可以用定时器定时)
})
function getArticleInfo(): Promise<Array<object>> {//从后台请求数据
    return new Promise((resolve, reject) => {
        request.get(api.GetArticleInfo, {
            id: route.params.id
        }).then(res => {
            resolve(res?.data?.data)
        }).catch(err => {
            reject(err)
        })
    })
}
</script>

引入完之后刷新你会发现还是没有添加行号

图片

官网已经说得很清楚,除了引入行号插件及样式,我们还需要指定一个line-numbers类,将这个类添加到pre标签或者他的祖先,只要他或他的祖先添加的了line-numbers那么他的子元素就会被行号插件自动添加line-numbers,从而达到添加行号。

图片

添加line-numbers类名到自己的项目,在这里我添加到了v-html要解析的那个标签上,因为后台返回的编辑数据都是在该标签内渲染,所以该标签属于pre标签的祖先元素,你也可以将line-numbers类名添加到该div的祖先父级元素中,又或者可以添加到body上,但建议添加到这个v-html要渲染的签上,因为只有该标签内的数据是要被渲染解析的。

<template>
    <div class="article-wrapper">
        <template v-for="item in articleInfoData">
            <h3 class="title">{{ item.title }}</h3>
            <p class="desc" v-if="item.desc">摘要:{{ item.desc }}</p>
            <section class="author">
                <span>作者:三叶雨</span>&nbsp;
                <span>{{ item.created_at }}</span>
            </section>
            <div class="content line-numbers" v-html="item.content"></div>
        </template>
    </div>
</template>

添加line-numbers类名后我们可以看到行号已经被添加上去,其他插件的使用方式同本插件,大家按需引入然后看对应的插件即可。

图片

五、Prismjs代码高亮的实现原理

在说原理之前我们应该弄明白的一个问题是,编辑器编辑的内容输出数据格式是怎么样的,这里以tinymce编辑器为例,我们可以发现返回给前台的数据是这样的,我们可以发现代码块被pre->code被这两个标签所包裹,简单来说就是prismjs是在pre->code

图片

从后台返回的编辑器内容数据

上做了一些处理,我们可以从prismjs的源码中可以发现,获取到pre->code之后,首先获取到pre标签类上的language-xxxx给对应语言的关键字用正则匹配替换或添加标签及相应的样式,这样就达到了代码高亮的效果。

图片

prism解析js的源码

图片

被prism解析后代码高亮的HTML源码

所以只要符合pre->code标签结构内的代码块都会被prism js解析高亮。

到此完结,希望能为你节省一些时间。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雨说前端

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值