本文将介绍编辑器的应用和随同的某些开发技巧。

该编辑器反对的性能有:根底的md编辑、md语法快捷键、记录保留、暗黑主题、图片上传/复制图片上传/裁剪图片上传、格式化内容、浏览器全屏/屏幕全屏、仅预览模式等性能,静待应用。

具体的编辑器api参考:文档。

  • 图片裁剪预览

  • 编辑器预览

1. 根本应用

这里演示两种环境三种写法:

1.1 npm装置用法

这种形式反对两种写法,除了.vue模板写法,还有jsx语法。

装置

yarn add md-editor-v3

.vue模板根底应用

<template>  <md-editor v-model="text" /> </template>  <script lang="ts"> import { defineComponent } from 'vue'; import MdEditor from 'md-editor-v3'; import 'md-editor-v3/lib/style.css';  export default defineComponent({   components: { MdEditor },   data() {     return { text: '' };   } }); </script>

jsx语法根底应用

import { defineComponent, ref } from 'vue';import MdEditor from 'md-editor-v3';import 'md-editor-v3/lib/style.css';export default defineComponent({  name: 'MdEditor',  setup() {    const text = ref('');    return () => (      <MdEditor modelValue={text.value} onChange={(v: string) => (text.value = v)} />    );  }});

1.2 script标签引入用法

链接可返回https://cdn.jsdelivr.net搜寻md-editor-v3

<!--增加款式--><link href="https://cdn.jsdelivr.net/npm/md-editor-v3@1.2.0/lib/style.css" rel="stylesheet" /><!--引入vue3--><script src="https://cdn.jsdelivr.net/npm/vue@3.1.5/dist/vue.global.prod.min.js"></script><!--引入组件--><script src="https://cdn.jsdelivr.net/npm/md-editor-v3@1.2.0/lib/md-editor-v3.umd.js"></script>

注册组件

const App = { data() {   return {      text: 'Hello Editor!!'   }; }};Vue.createApp(App).use(MdEditorV3).mount('#md-editor-v3');

应用组件

<div id="md-editor-v3">  <md-editor-v3 v-model="text" /></div>

2. 渲染内容

该编辑器应用marked解析mdhtml,没有扩大语法。

通常来讲,编辑内容存储为md格局,渲染内容时,通过marked解析为html。

2.1 默认渲染

1.3.0版本后,编辑器反对了previewOnly性能,能够间接应用编辑器预览文章,没有bar、编辑等等。

<template>  <md-editor    v-model="text"    previewOnly  /></template><script lang="ts">import { defineComponent } from 'vue';import MdEditor from 'md-editor-v3';import 'md-editor-v3/lib/style.css';export default defineComponent({  components: { MdEditor },  data() { return { text: '## 我只会显示预览内容' }; }});</script>

2.2 被动解析演示

这种形式用于保留md,而后自行解析md内容。

import marked from 'marked';// 代码高亮import hljs from 'highlight.js';// 自选代码高亮款式import 'highlight.js/scss/atom-one-dark.scss';// 用于记录题目数,依据业务代替let count = 0;// 记录题目内容const headstemp = [];// marked设置const rendererMD = new marked.Renderer();// 调整题目内容rendererMD.heading = (text, level) => {  headstemp.push({ text, level });  count++;  return `<h${level} id="heading-${count}"><span class="h-text">${text}</span></h${level}>`;};// 设置图片内容,对立显示一张缓存图,用于懒加载~rendererMD.image = (href, _, text) =>  `<img data-src="${href}" src="/cos/2020/1211175603.png" alt="${text}" >`;marked.setOptions({  highlight(code) {    return hljs.highlightAuto(code).value  },  renderer: rendererMD});// 这里的html就是插入到页面的元素文本了const html = marked('## md内容');

2.3 题目导航实现

下面的例子headstemp记录了解析过程中的所有题目,作用是借助UI库的组件Anchor,构建一个题目导航。

上面演示一个基于ant-design-vue的版本,如果你应用的UI库是相似的锚点组件,那么代码将只须要小改变即可。代码应用jsx语法,vue模板语法请自行拆散代码~

Recursive.tsx 导航中的链接组件

import { Anchor } from 'ant-design-vue';import { defineComponent, PropType } from 'vue';const { Link } = Anchor;export interface Head {  text: string;  level: number;}export interface TocItem extends Head {  anchor: string;  children?: Array<TocItem>;}const Recursive = defineComponent({  props: {    tocItem: {      type: Object as PropType<TocItem>,      default: () => []    }  },  setup({ tocItem }) {    return (      <Link href={`#${tocItem.anchor}`} title={tocItem.text}>        {tocItem.children &&          tocItem.children.map((item) => <Recursive key={item.anchor} tocItem={item} />)}      </Link>    );  }});export default Recursive;

Topicfy.tsx 用于生成整个导航内容

import { Anchor } from 'ant-design-vue';import { computed, defineComponent, PropType, ref, watch } from 'vue';import Recursive, { Head, TocItem } from './Recursive';const Topicfy = defineComponent({  props: {    // 解析失去的题目列表    heads: {      type: Array as PropType<Array<Head>>    }  },  setup(props) {    const topics = computed(() => {      const tocItems: TocItem[] = [];      // 题目计数器      let count = 0;      const add = (text: string, level: number) => {        count++;        const item = { anchor: `heading-${count}`, level, text };        if (tocItems.length === 0) {          // 第一个 item 间接 push          tocItems.push(item);        } else {          let lastItem = tocItems[tocItems.length - 1]; // 最初一个 item          if (item.level > lastItem.level) {            // item 是 lastItem 的 children            for (let i = lastItem.level + 1; i <= 6; i++) {              const { children } = lastItem;              if (!children) {                // 如果 children 不存在                lastItem.children = [item];                break;              }              // 重置 lastItem 为 children 的最初一个 item              lastItem = children[children.length - 1];              if (item.level <= lastItem.level) {                // item level 小于或等于 lastItem level 都视为与 children 同级                children.push(item);                break;              }            }          } else {            // 置于最顶级            tocItems.push(item);          }        }      };      props.heads?.forEach((item) => {        add(item.text, item.level);      });      return tocItems;    });    return () => (      <Anchor affix={false} showInkInFixed={true}>        {topics.value.map((item) => (          <Recursive key={item.anchor} tocItem={item} />        ))}      </Anchor>    );  }});export default Topicfy;
该组件是19年参考了网络上的实现实现的,非自己齐全原创,react版本参考Topicfy

2.4 获取html代码

编辑器思考到了可能后端不存储md格局的文本,而是html内容,所以提供了onHtmlChanged办法,用于编辑内容变动后,marked编译了内容的回调,入参即是html内容。

<template>  <md-editor    v-model="text"    @onHtmlChanged="saveHtml"  /></template><script lang="ts">import { defineComponent } from 'vue';import MdEditor from 'md-editor-v3';import 'md-editor-v3/lib/style.css';export default defineComponent({  components: { MdEditor },  data() { return { text: '' }; },  methods: { saveHtml(h: string) { console.log(h) }}});</script>

jsx语法雷同。

3. 编辑器的性能演示

3.1 扩大库链接

编辑器扩大内容大多应用了cdn,思考了无外网状况,反对了内网链接扩大,演示(假如内部库都在根目录下):

<template>  <md-editor    v-model="text"    highlightJs="/highlight.min.js"    highlightCss="/atom-one-dark.min.css"    prettierCDN="/standalone.js"    prettierMDCDN="/parser-markdown.js"    cropperJs="/cropper.min.js"    cropperCss="/cropper.min.css"  /></template><script lang="ts">import { defineComponent } from 'vue';import MdEditor from 'md-editor-v3';import 'md-editor-v3/lib/style.css';export default defineComponent({  components: { MdEditor },  data() { return { text: '' }; }});</script>
v1.2.0版本目前反对上述链接,图标链接将在后续补丁中增加。

3.2 工具栏自定义

默认的全副工具栏,并且每个性能都绑定了快捷键,如果须要选择性显示工具栏,提供了两个api:toolbarstoolbarsExclude,前者显示数组中的全副,后者屏蔽数组中的全副,后者的权重更大。上面是个参考:

案例不显示github按钮

<template>  <md-editor    v-model="text"    :toolbars="toobars"  />    <md-editor    v-model="text"    :toolbarsExclude="toolbarsExclude"  /></template><script lang="ts">import { defineComponent } from 'vue';import MdEditor from 'md-editor-v3';import 'md-editor-v3/lib/style.css';export default defineComponent({  components: { MdEditor },  data() {    return {      text: '',      toobars: ['bold', 'underline', 'italic', 'strikeThrough',      'sub','sup','quote','unorderedList', 'orderedList', 'codeRow',      'code', 'link', 'image', 'table', 'revoke',      'next', 'save', 'pageFullscreen', 'fullscreen',      'preview', 'htmlPreview'],      toolbarsExclude: ['github']    };  }});</script>

3.3 扩大语言

编辑器默认内置了中文和英文,并且两者都能够通过扩大api笼罩,该性能次要用来设置内容提醒,比方弹窗中的题目等。

扩大一门语言,咱们取名为zh-NB

<template>  <md-editor    v-model="text"    :language="language"    :languageUserDefined="languageUserDefined"  /></template><script lang="ts">import { defineComponent } from 'vue';import MdEditor, { StaticTextDefaultValue } from 'md-editor-v3';import 'md-editor-v3/lib/style.css';const languageUserDefined: { 'zh-NB': StaticTextDefaultValue } = {  'zh-NB': {    toolbarTips: {      bold: '加粗',      underline: '下划线',      italic: '斜体',      strikeThrough: '删除线',      title: '题目',      sub: '下标',      sup: '上标',      quote: '援用',      unorderedList: '无序列表',      orderedList: '有序列表',      codeRow: '行内代码',      code: '块级代码',      link: '链接',      image: '图片',      table: '表格',      revoke: '后退',      next: '后退',      save: '保留',      prettier: '丑化',      pageFullscreen: '浏览器全屏',      fullscreen: '屏幕全屏',      preview: '预览',      htmlPreview: 'html代码预览',      github: '源码地址'    },    titleItem: {      h1: '一级题目',      h2: '二级题目',      h3: '三级题目',      h4: '四级题目',      h5: '五级题目',      h6: '六级题目'    },    linkModalTips: {      title: '增加',      descLable: '链接形容:',      descLablePlaceHolder: '请输出形容...',      urlLable: '链接地址:',      UrlLablePlaceHolder: '请输出链接...',      buttonOK: '确定',      buttonUpload: '上传'    },    // v1.2.0新增    clipModalTips: {      title: '裁剪图片上传',      buttonUpload: '上传'    },    // v1.1.4新增    copyCode: {      text: '复制代码',      tips: '已复制'    }  }};export default defineComponent({  components: { MdEditor },  data() {    return {      text: '',      language: "zh-NB",      languageUserDefined    };  }});</script>
如果key = 'zh-CN',就能够实现中文笼罩,顺次类推。

3.4 主题切换

这一块绝对比较简单了,内置了暗黑主题默认主题,通过themeapi切换,demo如下:

<template>  <md-editor    v-model="text"    :theme="theme"  /></template><script lang="ts">import { defineComponent } from 'vue';import MdEditor from 'md-editor-v3';import 'md-editor-v3/lib/style.css';export default defineComponent({  components: { MdEditor },  data() {    return {      text: '',      theme: 'dark'    };  }});</script>

4. 结尾

更多的更新请关注:[md-editor-v3]()