Vue3集成Tinymce富文本和markdown编辑器,实现插入markdown数据的功能,实现富文本转为markdown的功能。
其中实现插入markdown的功能,最后采用了方案一和方案三。 方案一适用于在富文本编辑框中输入markdown的情况。方案三适用于把从其他渠道获取的markdown的大片文本黏贴进富文本的情况。 其中富文本转为markdown通过自定义插件的方法解决的,核心逻辑是获取到富文本编辑器的内容,把html转为markdown。
实现插入markdown的功能
方案一,使用插件
- 可以自己实现类似markdown类的文本语法结构 textpattern.
plugins:'textpattern',
textpattern_patterns: [
{ start: "*", end: "*", format: "italic" },
{ start: "**", end: "**", format: "bold" },
{ start: "#", format: "h1" },
{ start: "##", format: "h2" },
{ start: "###", format: "h3" },
{ start: "####", format: "h4" },
{ start: "#####", format: "h5" },
{ start: "######", format: "h6" },
{ start: "1. ", cmd: "InsertOrderedList" },
{ start: "* ", cmd: "InsertUnorderedList" },
{ start: "- ", cmd: "InsertUnorderedList" },
{ start: "\n", replacement: "<br/>" },
{ start: "---", replacement: "<hr/>" },
{ start: "--", replacement: "—" },
{ start: "-", replacement: "—" },
{ start: "(c)", replacement: "©" },
{ start: "//brb", replacement: "Be Right Back" },
{
start: "//heading",
replacement:
'<h1 style="color:blue">Heading here</h1><p><em>Date: 01/01/2000</em></p> ',
},
],
- 有三种匹配方式:
1 包围匹配
形如:{start: '**', end: '**', format: 'bold'} 即为包围匹配。
2 块匹配
形如:{start: '1. ', cmd: 'InsertOrderedList'}, 即为块匹配。
3 替换匹配
{start: '(c)', replacement: '©'} 为替换模式的写法。
- 缺陷是匹配方式,有三种匹配方式中不能处理以下内容一行中有多个标签的情况,如 “# 一级标题 /n ## 二级标题”。
方案二
- 使用官方插件tinymce markdown
- 不过需要版本7,而且需要付费。
方案三
marked
:转换markdown语法为HTMLhighlight.js
:高亮代码块
npm install marked @types/marked highlight.js -S
- 使用方法:src/App.vue .
- TinymceEditor是我封装的富文本组件。
<template>
<div class="doc-box">
<div>
<a-space wrap>
<a-input v-model:value="valueMarkedTest" style="width: 300px"></a-input>
<a-button type="primary" @click="handleInsertText">插入文本</a-button>
<a-button @click="handleInsertMarkdown">插入markdown</a-button>
<a-button type="text">Text Button</a-button>
<a-button type="link">Link Button</a-button>
</a-space>
<div v-html="markdownToHtml" class="markdown-body"></div>
</div>
<div class="editor-box">
<TinymceEditor :value="formData.content" @update:value="updateContent" />
</div>
</div>
</template>
<script setup>
import { shallowRef, ref, reactive } from "vue";
import TinymceEditor from "./components/MyTiny/index.vue";
import { marked } from "marked";
import hljs from "highlight.js";
import "highlight.js/styles/foundation.css";
const value = ref("heww loo");
const formData = reactive({
content: "",
});
const updateContent = (v) => {
formData.content = v;
console.log(`内容变更了:` + v);
};
const handleInsertText = () => {
formData.content = formData.content + " 插入的文本123 ";
};
const render = new marked.Renderer();
marked.setOptions({
renderer: render, // 这是必填项
gfm: true, // 启动类似于Github样式的Markdown语法
pedantic: false, // 只解析符合Markdwon定义的,不修正Markdown的错误
sanitize: false, // 原始输出,忽略HTML标签(关闭后,可直接渲染HTML标签)
// 高亮的语法规范
highlight: (code, lang) => hljs.highlight(code, { language: lang }).value,
});
const valueMarkedTest = ref("**Hello,World** \n# 一级菜单 \n ## 二级菜单 ");
const markdownToHtml = shallowRef("");
markdownToHtml.value = marked(valueMarkedTest.value);
// // markdown转为html后,直接更新到富文本内容中
const handleInsertMarkdown = () => {
markdownToHtml.value = marked(valueMarkedTest.value);
console.log(markdownToHtml.value);
formData.content = formData.content + markdownToHtml.value;
};
</script>
<style scoped>
.doc-box {
padding: 0;
height: 100%;
border: solid 1px red;
width: 100%;
height: 100%;
}
.markdown-body {
background-color: pink;
margin: 10px;
}
.editor-box {
margin-top: 10px;
width: 100%;
max-height: calc(100% - 60px);
border: solid 1px green;
padding: 0;
}
</style>
富文本转为markdown
- 使用自定义插件的方法引入该插件。具体使用方法: 自定义插件的方法见上一篇文章vue3中如何引入TinyMCE并更改自定义右键菜单。
1 在public下新建文件夹 public/tinymce/plugins/markdown 。
2 复制.js文件到该目录下。
当前我的版本是tinymce5.10.3 ,需要微调下addButton、addMenuItem方法。
3 在.vue组件中使用这个插件
plugins:'markdown',
contextmenu: "markdown",
toolbar:'markdown'
-
核心代码截图
-
转换前
-
转换后
源码
本文档中示例源码已上传到这里,供参考。