背景:大模型生成文章内容,需要使用富文本编辑器进行内容的编辑。其中敏感词汇需要标注,最后可以生成word、pdf等格式的文档。
调研
目前市面上有好多富文本编辑器,我们的需求是开源免费、不要二次开发(人力&时间有限)。本篇记录wangEditor实验。
Demo 过程
这里使用了 wangEditor 5 作为富文本编辑器。
| npm install @wangeditor/editor-for-vue@next --save
|
使用包中自带的组件,渲染如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <template> <div style="border: 1px solid #ccc; width: 100%; margin: 0 auto"> <Toolbar style="border-bottom: 1px solid #ccc" :editor="editorRef" :defaultConfig="toolbarConfig" mode="default" /> <Editor style="height: 500px; overflow-y: hidden" v-model="valueHtml" :defaultConfig="editorConfig" mode="default" @onCreated="handleCreated" @customPaste="customPaste" /> </div> <el-button style="margin: 0 auto" @click="getEditorHTML">提交</el-button> </template>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| import '@wangeditor/editor/dist/css/style.css' import { onBeforeUnmount, ref, shallowRef } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
const editorRef = shallowRef()
const valueHtml = ref('') const toolbarConfig = {} const editorConfig = ref({ placeholder: '请输入内容...', MENU_CONF: {} })
editorConfig.value.MENU_CONF['uploadImage'] = { async customUpload(file, insertFn) { console.log('上传图片', file) const base64 = URL.createObjectURL(file) insertFn(base64, 'img') } }
editorConfig.value.MENU_CONF['uploadVideo'] = { async customUpload(file, insertFn) { console.log('上传视频', file) } }
const handleCreated = (editor) => { editorRef.value = editor console.log(editorConfig.value.MENU_CONF, 'editorConfig.value') }
const customPaste = (editor, event, callback) => { const text = event.clipboardData.getData('text/plain') if (text) { editor.insertText(text) event.preventDefault() callback(false) } }
const getEditorHTML = () => { console.log(editorRef.value.getHtml()) }
onMounted(() => { setTimeout(() => { valueHtml.value = '<p>模拟 Ajax 异步设置内容 HTML</p>' }, 1500) })
onBeforeUnmount(() => { const editor = editorRef.value if (editor == null) return editor.destroy() })
|
隐藏菜单栏
官方有toolbar.getConfig().toolbarKeys
这个方法,但是在 vue3 中没有成功,不确定应该在什么时候调用。
实验发现,在菜单栏中通过网页元素查看data-menu-key
确定菜单栏的名字,然后在toolbarConfig
中设置excludeKeys
属性,将不需要的菜单栏隐藏。
| const toolbarConfig = { excludeKeys: ['emotion'] }
|
自动保存
监听 Ctr + S
| const keyDown = (event) => { let currentKey = event.keyCode || event.which if (currentKey === 83 && (event.ctrlKey || event.metaKey)) { event.preventDefault() console.log('ctrl S') } }
onMounted(() => { document.addEventListener('keydown', keyDown) })
|
生成文档并下载
word 文档
| npm install html-docx-js-typescript --save
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import { asBlob } from 'html-docx-js-typescript';
const exportDoc = async () => { const editor = editorRef.value const html = editor.getHtml() const value = `<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> ${html} </body> </html>` const data = await asBlob(value, { orientation: 'portrait' }) as Blob const a = document.createElement('a') a.href = window.URL.createObjectURL(data) a.setAttribute('download', 'document.docx') a.click() a.remove() }
|
结果如下:
结论
可实现全屏编辑;
可实现鼠标键盘复制粘贴功能;
可实现选中文字调出工具栏;
可实现代码高亮(可选语言,但是浮动框被工具栏遮挡住部分);
可实现本地上传图片,目前为 base64 保存和传输;
可实现初始化内容;
可实现隐藏菜单栏;
可实现键盘事件 ctrl S 触发自动报错;
可实现保存为 word 并下载,会保留基本格式(字体可能不行,需要安装字体?),会自动分页;
尝试生成pdf,失败(要么打开不了,要么就是纯html,没有变成有格式的文字);
附录
wangEditor 5
自动保存
Vue3+TS实现将html或富文本编辑器转为Word并下载
14款web前端常用的富文本编辑器插件
UEditor 是百度的项目,已于2023年6月暂停维护;