Vue.js 项目使用 vue-prism-editor 语法高亮与编辑器

记录一下在 Vue.js 项目中使用 vue-prism-editor 进行语法高亮显示代码,并兼具代码编辑功能。JavaScript 中有几个比较典型的语法高亮显示的代码库,例如 SHJS, SyntaxHighlighter, Rainbow,   highlight.js。本博客曾经使用过 SyntaxHighlighter 来显示日志中的示例代码,现今所采用的是基于 PHP 的 Crayon Syntax Highlighter。除了只为了高亮显示代码外,有时候还需处理在线编辑代码,许多年前试用过 CodeMirror, 而今天要上手 Prism.js 也能够支持代码编辑。 

官方 Demo: prism-editor.netlify.com
Codesandbox:  https://codesandbox.io/s/61yrlnlnmn

为了给 Vue.js 项目提供方便,有人专门做了一个 Vue.js 的插件 vue-prism-editor,本文直接使用该插件,而非直接使用 Prism.js。并且项目蓝本用 @vue/cli 4.4.6 的命令
$ vue create vue-prism-editor-demo
创建的,创建过程可参考 Flask 和 Vue.js 开发及整合部署实例创建 Vue 项目一节,此文简单些,就只选择 default (babel, eslint) 默认项来创建

完后启动服务
$ cd vue-prism-editor-demo
$ npm run serve
现在可访问 http://localhost:8080 来到了 Vue.js 的欢迎页面,接下来要应用 HelloWorld 页面来高亮显示代码。

先要安装 vue-prism-editor, 命令如下
$ npm install --save vue-prism-editor            # 会连带安装 vue-prism-editor 的 css
$ npm install --save prismjs                             # 上一步并不会安装 prismjs, 所以需手动安装它,它也会同时安装 css
yarn 的话是 yarn add vue-prism-editornpm install 时候需要 --save 或 -S,它会在 package.json 中的 dependencies 块中加上行
"vue-prism-editor": "^0.6.1", 
"prismjs": "^1.20.0"
接下来只要对 App.vue 进行改造, App.vue 的完整内容如下:
 1<template>
 2  <div id="app">
 3    <prism-editor v-model="code" language="js" lineNumbers></prism-editor>
 4  </div>
 5</template>
 6
 7<script>
 8import VuePrismEditor from 'vue-prism-editor';
 9import 'vue-prism-editor/dist/VuePrismEditor.css';
10import 'prismjs';
11import 'prismjs/themes/prism.css';
12import Vue from 'vue';
13
14Vue.component('prism-editor', VuePrismEditor);
15
16export default {
17  data() {
18    return {
19      code:
20`fetch('http://example.com/movies.json')
21  .then(response => response.json())
22  .then(data => console.log(data));
23`,
24    };
25  },
26};
27</script>

保存后,http://localhost:8080 自动刷新,现在看到的页面为

最后一行是直接在页面中输入的,证明那确实是一个 Editor, 是可编辑的,而且对于新输入内容也能进行实时的高亮显示。

vue-prism-editor 除了可编辑,语法加亮外,还有 Undo/Redo,大小自动调整,行号显示等。

我们可以切换显示主题,到底 prism 支持什么主题呢?查看 node_modules/prismjs/thems 目录下的文件
$ ls node_modules/prismjs/themes | sort
prism-coy.css
prism-dark.css
prism-funky.css
prism-okaidia.css
prism-solarizedlight.css
prism-tomorrow.css
prism-twilight.css
prism.css
于是我们可以把 App.vue 中的行
1import 'prismjs/themes/prism.css';

改为上面列出的任一个主题样式,比如
1import 'prismjs/themes/prism-twilight.css';

页面自动刷新,注意这时候要改用 Safari 之外的浏览器了, 反正 Safari 我测试是不支持样式的选择,换成 Chrome

如果要支持别的语言,可对 <prism-editor> 标签的 language 属性指定别的,如 java, json 等,查找当前  prism 支持哪些语言可用命令
ls node_modules/prismjs/components | grep 'min' | sort
列出,比如要支持 java,需先 import
1import 'prismjs/components/prism-java';

然后
1<prism-editor language="java></prism-editor>

使用中发现的几个问题:
  1. 对 Safari 的支持较差,Safari 下初始时可高亮显示代码,但编辑代码时不能实时着色,并且不能切换主题
  2. 如果不是用 v-model="code" 的方式,而是  :code="code", 在 Chrome 下编辑时也不能实时着色
  3. 显示大段代码时有问题,我测试的问题代码是 23M, 试图显示一个超大的 JSON 字符串,出现问题为
     1vue.runtime.esm.js?2b0e:619 [Vue warn]: Error in render: "RangeError: Maximum call stack size exceeded"
     2
     3found in
     4
     5---> <PrismEditor>
     6       <S3File> at src/views/S3File.vue
     7         <App> at src/App.vue
     8           <Root>
     9
    10vue.runtime.esm.js?2b0e:1888 RangeError: Maximum call stack size exceeded
    11    at normalizeArrayChildren (vue.runtime.esm.js?2b0e:2384)
    12    at normalizeChildren (vue.runtime.esm.js?2b0e:2359)
    13    at _createElement (vue.runtime.esm.js?2b0e:3400)
    14    at createElement (vue.runtime.esm.js?2b0e:3353)
    15    at vm._c (vue.runtime.esm.js?2b0e:3491)
    16    at Proxy.render (VuePrismEditor.common.js?431a:2291)
    17    at VueComponent.Vue._render (vue.runtime.esm.js?2b0e:3548)
    18    at VueComponent.updateComponent (vue.runtime.esm.js?2b0e:4066)
    19    at Watcher.get (vue.runtime.esm.js?2b0e:4479)
    20    at Watcher.run (vue.runtime.esm.js?2b0e:4554)
    这有点狠了,但目前还没有发现在超大内容时如何禁止语法高亮,所以加了个条件,凡是超过 5 M的字符串改用 textarea 来展示。

其他的 vue-prism-editor 相关的属性就只照抄官网了

属性

属性名类型默认值OptionsDescription
v-modelstring--设置要显示的代码,编辑时能实时着色
codestring""-要显示的代码,但编辑时不能实时着色
languageString"js"vue,html,md,ts + Prismjs Languagesls node_modules/prismjs/components | grep 'min' | sort | wc -l 查到能支持 210 种语言
lineNumbersBooleanfalse-是否显示行号
readonlyBooleanfalse-是否只读
emitEventsBooleanfalse-是否能触发事件
autoStyleLineNumbersBooleantrue-允许组件来设置行号的样式风格(不太明白)

事件

NameParametersDescription
change(code)当代码内容改变时触发

以下事件只有在 emitEvents 属性设置为 true 才会被触发

NameParametersDescription
keydown(event)在编辑器中按下键时触发
keyup(event)在编辑器中按键放开时触发
editor-click(event)在可编辑时点击即触发
永久链接 https://yanbin.blog/vue-js-vue-prism-editor/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。