likes
comments
collection
share

从零开始Vue3+Element Plus后台管理系统(十三)——富文本编辑器、Markdown编辑器、代码编辑器

作者站长头像
站长
· 阅读数 20

早就想着要放几个编辑器的Demo到项目中,这也是项目开始就立下的flag。

今天专门挑选了几款主流编辑器,包括绕不开的富文本编辑器,码农最爱的markdown编辑器,还有用途相对少的代码编辑器。

时间有限的情况下,仅引入4个编辑器到我的vue3项目中,尝试了一下基础功能,以及富文本编辑器上传图片的配置。实践证明使用过程并不复杂,也没有什么坑(也有可能是没有深入使用的缘故),再加上它们的文档都很详尽,还是值得推荐的。

Tinymce

www.tiny.cloud/docs/tinymc…

从零开始Vue3+Element Plus后台管理系统(十三)——富文本编辑器、Markdown编辑器、代码编辑器 Tinymce是我接触比较早的富文本编辑器,早在使用jq写页面的时候就使用过。迈入Vue3时代,Tinymce依然在与时俱进,只是使用越来越麻烦了,还要去官网注册一个账号,拿到Key,并且验证domain。

当然没有key也没关系,只是会有一个提示在编辑器上,不那么友好。如果你真的觉得在项目中使用tinymce再去注册也可以。

<template>
  <div>
    <PageHeader title="富文本编辑器 Tinymce">
      Version 4 and later of the tinymce-vue package supports Vue.js 3.x, but does not support
      Vue.js 2.x.
      <a href="https://www.tiny.cloud/docs/tinymce/6/vue-cloud/" target="_blank"
        >tiny docs
      </a></PageHeader
    >
    <div class="mx-4" v-loading="loading">
      <Editor v-model="content" :api-key="apiKey" :init="init" />
      <div class="mt-4 text-center"><el-button @click="save">保存</el-button></div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import Editor from '@tinymce/tinymce-vue'

const apiKey = 'xxx'
const example_image_upload_handler = (blobInfo, progress) =>
  new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest()
    xhr.withCredentials = false
    xhr.open('POST', 'https://mock.apifox.cn/m1/2700315-0-default/uploadTiny')

    xhr.upload.onprogress = (e) => {
      progress((e.loaded / e.total) * 100)
    }

    xhr.onload = () => {
      if (xhr.status === 403) {
        reject({ message: 'HTTP Error: ' + xhr.status, remove: true })
        return
      }

      if (xhr.status < 200 || xhr.status >= 300) {
        reject('HTTP Error: ' + xhr.status)
        return
      }

      const json = JSON.parse(xhr.responseText)

      if (!json || typeof json.location != 'string') {
        reject('Invalid JSON: ' + xhr.responseText)
        return
      }

      resolve(json.location)
    }

    xhr.onerror = () => {
      reject('Image upload failed due to a XHR Transport error. Code: ' + xhr.status)
    }

    const formData = new FormData()
    formData.append('file', blobInfo.blob(), blobInfo.filename())

    xhr.send(formData)
  })

let loading = ref(true)
function afterInit() {
  loading.value = false
}

const init = {
  language: 'zh_CN',
  plugins: 'lists link image table code help wordcount',
  init_instance_callback: afterInit,
  toolbar: [
    // 数组写法
    'undo redo | formatselect | bold italic underline strikethrough | fontsizeselect | hr bullist numlist outdent indent blockquote subscript superscript | alignleft | aligncenter | alignright | image media | selectall codesample fullscreen preview searchreplace',
    'table tabledelete | tableprops tablerowprops tablecellprops | tableinsertrowbefore tableinsertrowafter tabledeleterow | tableinsertcolbefore tableinsertcolafter tabledeletecol'
  ],
  // images_upload_url: 'https://mock.apifox.cn/m1/2700315-0-default/uploadTiny',
  // images_upload_base_path: '/demo',
  images_upload_handler: example_image_upload_handler
}

let content = ref()
function save() {
  console.log(content.value)
}
</script>

wangEditor

www.wangeditor.com/

从零开始Vue3+Element Plus后台管理系统(十三)——富文本编辑器、Markdown编辑器、代码编辑器

个人感觉 wangEditor 更友好,引入过程很简单,加载速度优于tinymce,还不用注册key,最重要的是文档是中文的😄,所以大概率会选择在项目中使用wangEditor。

<template>
  <div>
    <PageHeader title="富文本编辑器 wangEditor">
      wangEditor:轻量级 web 富文本编辑器,配置方便,使用简单。
      <a href="https://www.wangeditor.com/" target="_blank">wangEditor docs</a></PageHeader
    >
    <div class="mx-4 shadow">
      <Toolbar
        style="border-bottom: 1px solid #ccc"
        :editor="editorRef"
        :defaultConfig="toolbarConfig"
        :mode="mode"
      />
      <Editor
        style="height: 500px; overflow-y: hidden"
        v-model="valueHtml"
        :defaultConfig="editorConfig"
        :mode="mode"
        @onCreated="handleCreated"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import '@wangeditor/editor/dist/css/style.css' // 引入 css

import { onBeforeUnmount, ref, shallowRef, onMounted } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import PageHeader from '~/components/UI/PageHeader.vue'

const mode = 'default' // 或 'simple'

// 编辑器实例,必须用 shallowRef
const editorRef = shallowRef()

// 内容 HTML
const valueHtml = ref('<p>hello</p>')

// 模拟 ajax 异步获取内容
onMounted(() => {
  setTimeout(() => {
    valueHtml.value = '<p>模拟 Ajax 异步设置内容</p>'
  }, 1500)
})

const toolbarConfig = {}
const editorConfig = {
  placeholder: '请输入内容...',
  MENU_CONF: {
    uploadImage: {
      // mock地址
      server: 'https://mock.apifox.cn/m1/2700315-0-default/upload',
      // 小于该值就插入 base64 格式(而不上传),默认为 0
      base64LimitSize: 20 * 1024 // 20kb
    }
  }
}

// 组件销毁时,也及时销毁编辑器
onBeforeUnmount(() => {
  const editor = editorRef.value
  if (editor == null) return
  editor.destroy()
})

const handleCreated = (editor) => {
  editorRef.value = editor // 记录 editor 实例,重要!
}
</script>

md-editor

imzbf.github.io/md-editor-v…

从零开始Vue3+Element Plus后台管理系统(十三)——富文本编辑器、Markdown编辑器、代码编辑器

配置简单,功能够用,外观清爽,拿来即用,这也是我代码写的最少的一个demo。

<md-editor v-model="text" @on-upload-img="onUploadImg" />

<script setup lang="ts">
import { ref } from 'vue'
import MdEditor from 'md-editor-v3'
import 'md-editor-v3/lib/style.css'

const text = ref('Hello Editor!')
const onUploadImg = (files: any) => {
  console.log(files)
}
</script>

codemirror

codemirror.net/

从零开始Vue3+Element Plus后台管理系统(十三)——富文本编辑器、Markdown编辑器、代码编辑器 codemirror是今天花时间最多的编辑器了,因为英文文档没看太明白,网上的文章也相对少一点。不过我又不是需要打造一个IDE,基础功能可以满足日常需要就好。一般来说,我只是用Codemirror预览代码,做少量编辑工作。

本项目使用的是vue-codemirror,CodeMirror(6) component for Vue(3)

<template>
  <div>   
    <div class="mx-4">
      <el-tabs @tab-change="changeMode">
        <el-tab-pane v-for="item in modeList" :label="item.lan"></el-tab-pane>
      </el-tabs>
      <codemirror
        v-model="code"
        placeholder="Code gose here..."
        :lineNumbers="false"
        :style="{ height: '400px' }"
        :autofocus="true"
        :indent-with-tab="true"
        :tabSize="2"
        :extensions="extensions"
        @ready="log('ready', $event)"
        @change="log('change', $event)"
        @focus="log('focus', $event)"
        @blur="log('blur', $event)"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import { Codemirror } from 'vue-codemirror'
import { javascript } from '@codemirror/lang-javascript'
import { python } from '@codemirror/lang-python'
import { css } from '@codemirror/lang-css'
import { html } from '@codemirror/lang-html'
import { oneDark } from '@codemirror/theme-one-dark'
import { ref } from 'vue'

const modeList = [
  { lan: 'javascript', ex: javascript() },
  { lan: 'css', ex: css() },
  { lan: 'html', ex: html() },
  { lan: 'python', ex: python() }
]

const code = ref(`console.log('Hello, world!')`)
const extensions = ref([python(), oneDark])

function log(str: string, event: Event) {
  console.log(str)
}

function changeMode(e: number) {
  extensions.value = [modeList[e].ex, oneDark]
}
</script>

从零开始Vue3+Element Plus后台管理系统(十三)——富文本编辑器、Markdown编辑器、代码编辑器

如果有帮助,给个star ✨ 点个赞👍