从零开始Vue3+Element Plus后台管理系统(十三)——富文本编辑器、Markdown编辑器、代码编辑器
早就想着要放几个编辑器的Demo到项目中,这也是项目开始就立下的flag。今天专门挑选了几款主流编辑器,包括绕不开的富文本编辑器,码农最爱的markdown编辑器,还有用途相对少的代码编辑器。时间有限的情况下,仅引入4个编辑器到我的vue3项目中,尝试了一下基础功能,以及富文本编辑器上传图片的配置。实践证明使用过程并不复杂,也没有什么坑(也有可能是没有深入使用的缘故),再加上它们的文档都很详尽,还
早就想着要放几个编辑器的Demo到项目中,这也是项目开始就立下的flag。
今天专门挑选了几款主流编辑器,包括绕不开的富文本编辑器,码农最爱的markdown编辑器,还有用途相对少的代码编辑器。
时间有限的情况下,仅引入4个编辑器到我的vue3项目中,尝试了一下基础功能,以及富文本编辑器上传图片的配置。实践证明使用过程并不复杂,也没有什么坑(也有可能是没有深入使用的缘故),再加上它们的文档都很详尽,还是值得推荐的。
Tinymce
https://www.tiny.cloud/docs/tinymce/6/vue-cloud/
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
https://www.wangeditor.com/
个人感觉 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
https://imzbf.github.io/md-editor-v3/en-US/index
配置简单,功能够用,外观清爽,拿来即用,这也是我代码写的最少的一个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
https://codemirror.net/
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>
本项目GIT地址:github.com/lucidity99/…
如果有帮助,给个star ✨ 点个赞👍
更多推荐
所有评论(0)