当前位置:   article > 正文

vue3中使用cherry-markdown

vue3中使用cherry-markdown

附cherry-markdown官网及api使用示例

官网:https://github.com/Tencent/cherry-markdown/blob/main/README.CN.md

api:Cherry Markdown API

考虑到复用性,我在插件的基础上做了二次封装,步骤如下:

1.下载 (一定要指定版本0.8.22,否则会报错: [vitel Internal server error: Failed to parse soERRORrce for import analysis because the content contains invalid Js syntax. If you are using JSX, make sure to name the file with the...

npm i cherry-markdown@0.8.22

如果需要开启 mermaid 画图、表格自动转图表功能,需要同时添加mermaid 与echarts包。

目前Cherry推荐的插件版本为echarts@5.3.3mermaid@9.4.3

# 安装mermaid依赖开启mermaid画图功能

npm i mermaid@9.4.3

# 安装echarts依赖开启表格自动转图表功能

npm i echarts@5.3.3

基础应用代码示例

  1. <template>
  2. <div @click.prevent.stop>
  3. <div id="markdown-container"></div>
  4. </div>
  5. </template>
  6. <script>
  7. import 'cherry-markdown/dist/cherry-markdown.css';
  8. import Cherry from 'cherry-markdown';
  9. const cherryInstance = new Cherry({
  10. id: 'markdown-container',
  11. value: '# welcome to cherry editor!',
  12. });
  13. </script>

关于 mermaid(插件注册必须在Cherry实例化之前完成

核心构建包不包含 mermaid 依赖,需要手动引入相关插件。

  1. import 'cherry-markdown/dist/cherry-markdown.css';
  2. import Cherry from 'cherry-markdown/dist/cherry-markdown.core';
  3. import CherryMermaidPlugin from 'cherry-markdown/dist/addons/cherry-code-block-mermaid-plugin';
  4. import mermaid from 'mermaid';
  5. // 插件注册必须在Cherry实例化之前完成
  6. Cherry.usePlugin(CherryMermaidPlugin, {
  7. mermaid, // 传入mermaid引用
  8. // mermaidAPI: mermaid.mermaidAPI, // 也可以传入mermaid API
  9. // 同时可以在这里配置mermaid的行为,可参考mermaid官方文档
  10. // theme: 'neutral',
  11. // sequence: { useMaxWidth: false, showSequenceNumbers: true }
  12. });
  13. const cherryInstance = new Cherry({
  14. id: 'markdown-container',
  15. value: '# welcome to cherry editor!',
  16. });

2.附上组件代码

  1. <template>
  2. <div @click.prevent.stop style="position: relative; width: 100%; height: 100%; z-index: 9999999999;text-align: left;">
  3. <!-- ------- markdown组件容器 --------- -->
  4. <div ref="markdownContainerRef" :id="mdId" class="cherry_container scroll"
  5. :style="{ 'left': toc_Visiable ? '262px' : '0px' }" @scroll="onScroll">
  6. </div>
  7. <!-- ------- 显示目录 --------- -->
  8. <!-- <div class="toc_container" v-show="toc_Visiable">
  9. <div class="toc_header">目录</div>
  10. <div class="toc_list">
  11. <div v-for="(link, index) in toc_List" :key="link.id" class="toc_list_container"
  12. :style="{ 'padding-left': link.level * 20 + 'px' }" @click="jump(index)">{{ link.text }}
  13. </div>
  14. </div>
  15. </div>
  16. <div class="top-contrl">
  17. <div v-if="!toc_Visiable" @click="showToc(true)">显示目录</div>
  18. <div v-else @click="showToc(false)">隐藏目录</div>
  19. </div> -->
  20. </div>
  21. </template>
  22. <script setup>
  23. import { ref, onMounted, onBeforeMount, watch, onBeforeUnmount, toRefs, reactive, nextTick } from 'vue';
  24. import Axios from 'axios';
  25. import 'cherry-markdown/dist/cherry-markdown.css';
  26. import Cherry from 'cherry-markdown'
  27. // import Cherry from 'cherry-markdown/dist/cherry-markdown.core';
  28. import * as echarts from "echarts";
  29. import pinyin from '../assets/pinyinHelper.js'; // 引入pinyin函数
  30. import CherryMermaidPlugin from 'cherry-markdown/dist/addons/cherry-code-block-mermaid-plugin';
  31. import mermaid from 'mermaid';
  32. // 组件传值
  33. const props = defineProps({
  34. // markdown文本
  35. markDownConent: {
  36. type: String,
  37. default: '',
  38. },
  39. // markdown组件容器ID
  40. mdId: {
  41. type: String,
  42. default: 'markdownContainer',
  43. },
  44. // 编辑器的显示模式 view|edit
  45. displayModal: {
  46. type: String,
  47. default: 'view',
  48. },
  49. // 用来控制目录显示或隐藏
  50. tocVisiable: {
  51. type: Boolean,
  52. default: true,
  53. },
  54. });
  55. const emit = defineEmits(['input', 'md-change']);
  56. const { mdId, displayModal, tocVisiable, markDownConent } = toRefs(props);
  57. // 组件内部变量
  58. const content = ref('');
  59. const markdownContainerRef = ref(null); //dom 元素
  60. const markDown_Conent = ref('');
  61. const toc_Visiable = ref(tocVisiable.value); //目录 显隐
  62. const cherrInstance = ref(null); //Cherry MarkDown实例
  63. const initCherryMD = async (value) => {
  64. markDown_Conent.value = value || markDownConent.value;
  65. cherrInstance.value = new Cherry({
  66. id: mdId.value,
  67. value: markDown_Conent.value,
  68. externals: {
  69. echarts: echarts,
  70. },
  71. fileUpload,
  72. callback: {
  73. changeString2Pinyin: pinyin,
  74. // afterChange,
  75. afterInit,
  76. beforeImageMounted,
  77. onClickPreview: function (e) {
  78. const { target } = e;
  79. if (target.tagName === 'IMG') {
  80. console.log('click img', target);
  81. const tmp = new Viewer(target, {
  82. button: false,
  83. navbar: false,
  84. title: [1, (image, imageData) => `${image.alt.replace(/#.+$/, '')} (${imageData.naturalWidth} × ${imageData.naturalHeight})`],
  85. hidden() {
  86. tmp.destroy()
  87. },
  88. });
  89. tmp.show();
  90. }
  91. }
  92. },
  93. toolbars: {
  94. showToolbar:displayModal.value=="previewOnly"?false:true,
  95. toolbar: ['bold', 'italic', 'strikethrough', '|', 'color', 'header', 'ruby', '|', 'list', 'panel', 'detail'],
  96. // 定义侧边栏,默认为空
  97. sidebar: [],
  98. // 定义顶部右侧工具栏,默认为空
  99. toolbarRight: [],
  100. // 定义选中文字时弹出的“悬浮工具栏”,默认为 ['bold', 'italic', 'underline', 'strikethrough', 'sub', 'sup', 'quote', '|', 'size', 'color']
  101. bubble: false,
  102. // 定义光标出现在行首位置时出现的“提示工具栏”,默认为 ['h1', 'h2', 'h3', '|', 'checklist', 'quote', 'table', 'code']
  103. float: false,
  104. // 定义顶部工具栏
  105. toolbar: [
  106. 'bold',
  107. 'italic',
  108. {
  109. strikethrough: ['strikethrough', 'underline', 'sub', 'sup', 'ruby', 'boldAndItalicName'],
  110. },
  111. 'size',
  112. '|',
  113. 'color',
  114. 'header',
  115. '|',
  116. 'ol',
  117. 'ul',
  118. 'checklist',
  119. 'panel',
  120. 'justify',
  121. 'detail',
  122. '|',
  123. 'formula',
  124. {
  125. insert: ['image', 'audio', 'video', 'link', 'hr', 'br', 'code', 'formula', 'toc', 'table', 'pdf', 'word', 'ruby'],
  126. },
  127. 'graph',
  128. 'togglePreview',
  129. 'settings',
  130. 'codeTheme',
  131. 'export',
  132. // {
  133. // customMenuBName: ['ruby', 'audio', 'video', 'boldAndItalicName'],
  134. // },
  135. // 'customMenuCName',
  136. 'theme',
  137. ],
  138. // 定义侧边栏,默认为空
  139. sidebar: ['mobilePreview', 'copy', 'theme'],
  140. // 定义顶部右侧工具栏,默认为空
  141. toolbarRight: ['fullScreen', '|'],
  142. // 定义选中文字时弹出的“悬浮工具栏”,默认为 ['bold', 'italic', 'underline', 'strikethrough', 'sub', 'sup', 'quote', '|', 'size', 'color']
  143. bubble: ['bold', 'italic', 'underline', 'strikethrough', 'sub', 'sup', 'quote', 'ruby', '|', 'size', 'color'], // array or false
  144. showToolbar: true,
  145. // 定义光标出现在行首位置时出现的“提示工具栏”,默认为 ['h1', 'h2', 'h3', '|', 'checklist', 'quote', 'table', 'code']
  146. // float: false,
  147. toc: {
  148. updateLocationHash: false, // 要不要更新URL的hash
  149. defaultModel: 'full', // pure: 精简模式/缩略模式,只有一排小点; full: 完整模式,会展示所有标题
  150. },
  151. customMenu: {
  152. boldAndItalicName: boldAndItalic,
  153. customMenuBName: customMenuB,
  154. customMenuCName: customMenuC,
  155. },
  156. },
  157. editor: {
  158. id: `${mdId.value}editor`,
  159. name: 'cherry-text',
  160. autoSave2Textarea: true,
  161. defaultModel: displayModal.value,
  162. },
  163. previewer: {
  164. // 自定义markdown预览区域class
  165. // className: 'markdown'
  166. },
  167. // 预览页面不需要绑定事件
  168. isPreviewOnly: false,
  169. // 预览区域跟随编辑器光标自动滚动
  170. autoScrollByCursor: true,
  171. // 外层容器不存在时,是否强制输出到body上
  172. forceAppend: true,
  173. // The locale Cherry is going to use. Locales live in /src/locales/
  174. locale: 'zh_CN',
  175. keydown: [],
  176. // cherry初始化后是否检查 location.hash 尝试滚动到对应位置
  177. autoScrollByHashAfterInit: false,
  178. });
  179. };
  180. /**
  181. * 自定义一个自定义菜单
  182. * 点第一次时,把选中的文字变成同时加粗和斜体
  183. * 保持光标选区不变,点第二次时,把加粗斜体的文字变成普通文本
  184. */
  185. const boldAndItalic = Cherry.createMenuHook('加粗斜体', {
  186. iconName: 'font',
  187. onClick: function (selection) {
  188. // 获取用户选中的文字,调用getSelection方法后,如果用户没有选中任何文字,会尝试获取光标所在位置的单词或句子
  189. let $selection = this.getSelection(selection) || '同时加粗斜体';
  190. // 如果是单选,并且选中内容的开始结束内没有加粗语法,则扩大选中范围
  191. if (!this.isSelections && !/^\s*(\*\*\*)[\s\S]+(\1)/.test($selection)) {
  192. this.getMoreSelection('***', '***', () => {
  193. const newSelection = this.editor.editor.getSelection();
  194. const isBoldItalic = /^\s*(\*\*\*)[\s\S]+(\1)/.test(newSelection);
  195. if (isBoldItalic) {
  196. $selection = newSelection;
  197. }
  198. return isBoldItalic;
  199. });
  200. }
  201. // 如果选中的文本中已经有加粗语法了,则去掉加粗语法
  202. if (/^\s*(\*\*\*)[\s\S]+(\1)/.test($selection)) {
  203. return $selection.replace(/(^)(\s*)(\*\*\*)([^\n]+)(\3)(\s*)($)/gm, '$1$4$7');
  204. }
  205. /**
  206. * 注册缩小选区的规则
  207. * 注册后,插入“***TEXT***”,选中状态会变成“***【TEXT】***”
  208. * 如果不注册,插入后效果为:“【***TEXT***】”
  209. */
  210. this.registerAfterClickCb(() => {
  211. this.setLessSelection('***', '***');
  212. });
  213. return $selection.replace(/(^)([^\n]+)($)/gm, '$1***$2***$3');
  214. }
  215. });
  216. /**
  217. * 定义一个空壳,用于自行规划cherry已有工具栏的层级结构
  218. */
  219. const customMenuB = Cherry.createMenuHook('实验室', {
  220. iconName: '',
  221. });
  222. /**
  223. * 定义一个自带二级菜单的工具栏
  224. */
  225. const customMenuC = Cherry.createMenuHook('帮助中心', {
  226. iconName: 'question',
  227. onClick: (selection, type) => {
  228. switch (type) {
  229. case 'shortKey':
  230. console.log("
    声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/580649
    推荐阅读
    相关标签