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>
<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解析高亮。
到此完结,希望能为你节省一些时间。