Toast-UI/Editor工具实现图片自定义上传到服务器
author: jwensh
date: 2021.06.17
文章目录
- Toast-UI/Editor工具实现图片自定义上传到服务器
- 所遇问题
- 需要解决问题
- 1. 原 `toast-ui` 怎么处理上面三个操作的?
- 2. 重写其中监听事件
- 3. 服务端实现上传逻辑
- 4. 前端具体的实现
- 参考
所遇问题
在项目开发用到富文本框,期间使用过 Tinymce 和 toast-ui/editor(一款支持Markdown、WYSIWYG模式的编辑器),最后选择了
toast-ui
,这里不介绍两者的区别,主要感觉它好用。遇到的问题是:富文本编辑内容时,相关资源(img、video等)如何上传到指定服务器上?
-
Toast UI Editor 版本
"@toast-ui/editor": "2.5.2"
-
VUE2
工程里使用组件和插件npm install @toast-ui/editor
需要解决问题
- 找到编辑器中所有涉及到资源文件的操作:
图片上传
、截图粘贴
、图片拖入
- 将上诉操作都使用自定义操作
1. 原 toast-ui
怎么处理上面三个操作的?
默认使用
addImageBlobHook
监听事件将图片转换成Base64
追加到文本中
Toast UI Editor
支持三种图片上传方式:弹窗选择
、拖拽
、截屏粘贴
;三种上传方式最终都会被 addImageBlobHook
监听,并处理为 Base64
格式的图片;
- 此处为默认的
addImageBlobHook
监听事件,位于 src/js/ 中 第:124 行
/**
* Initialize default image importer
* @private
*/
_initDefaultImageImporter() {
('addImageBlobHook', (blob, callback) => {
const reader = new FileReader();
= event => {
callback();
};
(blob);
});
}
2. 重写其中监听事件
- 先看下是否有事件相关的设置方法
-
中提供了删除监听事件的函数
removeEventHandler(typeStr, handler)
第 210行
/**
* Remove event handler from given event type
* @param {string} typeStr Event type name
* @param {function} [handler] - registered event handler
*/
removeEventHandler(typeStr, handler) {
const { type, namespace } = this._getTypeInfo(typeStr);
if (type && handler) {
this._removeEventHandlerWithHandler(type, handler);
} else if (type && !namespace) {
// dont use dot notation cuz eslint
(type);
} else if (!type && namespace) {
((eventHandlers, eventType) => {
this._removeEventHandlerWithTypeInfo(eventType, namespace);
});
} else if (type && namespace) {
this._removeEventHandlerWithTypeInfo(type, namespace);
}
}
- 所以,第一步:去掉默认的
addImageBlobHook
监听事件
// 删除默认监听事件
('addImageBlobHook')
- 第二步:添加自定义的
addImageBlobHook
监听事件
// 添加自定义监听事件
('addImageBlobHook', (blob, callback) => {
// 此处填写自己的上传逻辑,url为上传后的图片地址
(blob, url => {
callback(url)
})
})
3. 服务端实现上传逻辑
后端服务实现一个可以上传文件的接口,单文件上传即可;语言自行选择,静态文件可以使用 nginx
挂载
4. 前端具体的实现
- vue的源码
<template>
<div : />
</template>
<script>
/**
* @author jwensh
* 这里使用 @toast-ui/editor@v2.5.2 版本的markdown编辑器
*/
import 'codemirror/lib/' // Editor's Dependency Style
import '@toast-ui/editor/dist/' // Editor's Style
import Editor from '@toast-ui/editor'
import defaultOptions from './default-options'
export default {
name: 'MarddownEditor',
props: {
value: {
type: String,
default: ''
},
id: {
type: String,
required: false,
default() {
return 'markdown-editor-' + +new Date() + ((() * 1000).toFixed(0) + '')
}
},
options: {
type: Object,
default() {
return defaultOptions
}
},
mode: {
type: String,
default: 'wysiwyg'
},
height: {
type: String,
required: false,
default: '300px'
},
language: {
type: String,
required: false,
default: 'en_US'
}
},
data() {
return {
editor: null
}
},
computed: {
editorOptions() {
const options = ({}, defaultOptions, )
=
=
=
return options
}
},
watch: {
value(newValue, preValue) {
if (newValue !== preValue && newValue !== ()) {
(newValue)
}
},
language(val) {
()
()
},
height(newValue) {
(newValue)
},
mode(newValue) {
(newValue)
}
},
mounted() {
()
},
methods: {
initEditor() {
= new Editor({
el: (),
...
})
if () {
()
}
('blur', () => {
this.$emit('updateContent', ())
})
// 删除默认监听事件后,添加自定义监听事件
('addImageBlobHook')
('addImageBlobHook', (blob, callback) => {
// 此处填写自己的上传逻辑,url为上传后的图片地址
const formData = new FormData()
('files', blob)
const ajax = new XMLHttpRequest()
('POST', 'http://***/v1/uploadfiles?user_id=jwensh', true)
(formData)
= function() {
if ( === 4) {
if (( >= 200 && < 300) || === 304) {
const obj = ()
if ( && === 'true') {
callback(.root_path + )
}
}
}
}
})
}
}
}
</script>
到此算是解决三种方式(Popup、Drag、Screenshot)按照自己的上传逻辑进行图片上传
参考
- /nhn/
- //latest/tutorial-example01-editor-basic