<template>
<div style="border: 1px solid #ccc;">
<Toolbar
class="toolbar-wrapper"
:editor="editor"
:default-config="toolbarConfig"
:mode="mode"
/>
<Editor
v-model="html"
class="editor-wrapper"
:default-config="editorConfig"
:mode="mode"
@onCreated="onCreated"
@onChange="onChange"
@customPaste="customPaste"
/>
</div>
</template>
<script>
import Vue from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { uploadFile } from '@/api/platform-organizational'
export default Vue.extend({
components: { Editor, Toolbar },
props: {
content: {
type: String,
default: ''
}
},
data() {
return {
editor: null,
html: null,
toolbarConfig: {
/* 显示哪些菜单,如何排序、分组 */
toolbarKeys: [
'headerSelect',
// '|',
'bold',
'underline',
'italic',
'color',
'bgColor',
// '|',
'indent', // 增加缩进
'delIndent', // 减少缩进
'justifyLeft', // 左对齐
'justifyRight', // 右对齐
'justifyCenter', // 居中
'justifyJustify', // 两端对齐
// '|',
'fontSize',
'fontFamily',
'lineHeight',
// '|',
'bulletedList',
'numberedList',
'todo',
'insertLink',
'insertTable',
// '|',
'codeBlock',
'divider',
'uploadImage',
'undo',
'redo'
],
excludeKeys: [] /* 隐藏哪些菜单 */
},
editorConfig: {
placeholder: '请输入内容...',
// 所有的菜单配置,都要在 MENU_CONF 属性下
MENU_CONF: {
// 配置上传图片
uploadImage: {
// 自定义上传图片 方法
customUpload: this.uploaadImg
}
}
},
mode: 'default' // or 'simple'
}
},
mounted() {
},
// 组件销毁时,及时销毁编辑器
beforeDestroy() {
const editor = this.editor
if (editor == null) return
editor.destroy()
},
methods: {
// 编辑器创建完毕时的回调函数
onCreated(editor) {
this.editor = Object.seal(editor) // 一定要用 Object.seal() ,否则会报错
this.$nextTick(() => {
this.html = this.content
})
},
// 上传图片
uploaadImg(file, insertFn) {
const formData = new FormData()
formData.append('isPublic', true)
formData.append('file', file)
uploadFile(formData).then(res => {
insertFn(res.downloadUrl)
})
},
// 编辑器内容、选区变化时的回调函数。
onChange(editor) {
this.$emit('changeData', this.html)
},
// 重点来了: 自定义粘贴。可阻止编辑器的默认粘贴,实现自己的粘贴逻辑。(可以实现复制粘贴 word ,有图片)
customPaste(editor, event, callback) {
let html = event.clipboardData.getData('text/html') // 获取粘贴的 html
// let text = event.clipboardData.getData('text/plain') // 获取粘贴的纯文本
const rtf = event.clipboardData.getData('text/rtf') // 获取 rtf 数据(如从 word wsp 复制粘贴)
var that = this
if (html && rtf) {
// 列表缩进会超出边框,直接过滤掉
html = html.replace(/text\-indent:\-(.*?)pt/gi, '')
// 从html内容中查找粘贴内容中是否有图片元素,并返回img标签的属性src值的集合
const imgSrcs = that.findAllImgSrcsFromHtml(html)
// 如果有
if (imgSrcs && Array.isArray(imgSrcs) && imgSrcs.length) {
// 从rtf内容中查找图片数据
const rtfImageData = that.extractImageDataFromRtf(rtf)
// 如果找到
if (rtfImageData.length) {
// TODO:此处可以将图片上传到自己的服务器上
rtfImageData.forEach((item, index) => {
this.uploadAllImage(item).then((res) => {
// 执行替换:将html内容中的img标签的src替换成ref中的图片数据,如果上面上传了则为图片路径
// res 是上传在服务器里返回的地址
html = html.replace(imgSrcs[index], res)
editor.dangerouslyInsertHtml(html)
})
})
}
}
// 阻止默认的粘贴行为
event.preventDefault()
return false
} else {
return true
}
},
/**
* 从html代码中匹配返回图片标签img的属性src的值的集合
* @param htmlData
* @return Array
*/
findAllImgSrcsFromHtml(htmlData) {
const imgReg = /<img.*?(?:>|\/>)/gi // 匹配图片中的img标签
const srcReg = /src=[\'\"]?([^\'\"]*)[\'\"]?/i // 匹配图片中的src
const arr = htmlData.match(imgReg) // 筛选出所有的img
if (!arr || (Array.isArray(arr) && !arr.length)) {
return false
}
const srcArr = []
for (let i = 0; i < arr.length; i++) {
const src = arr[i].match(srcReg)
// 获取图片地址
srcArr.push(src[1])
}
return srcArr
},
/**
* 从rtf内容中匹配返回图片数据的集合
* @param rtfData
* @return Array
*/
extractImageDataFromRtf(rtfData) {
if (!rtfData) {
return []
}
const regexPictureHeader =
/{\\pict[\s\S]+?({\\\*\\blipuid\s?[\da-fA-F]+)[\s}]*/
const regexPicture = new RegExp(
'(?:(' + regexPictureHeader.source + '))([\\da-fA-F\\s]+)\\}',
'g'
)
const images = rtfData.match(regexPicture)
const result = []
if (images) {
for (const image of images) {
let imageType = false
if (image.includes('\\pngblip')) {
imageType = 'image/png'
} else if (image.includes('\\jpegblip')) {
imageType = 'image/jpeg'
}
if (imageType) {
result.push({
hex: image
.replace(regexPictureHeader, '')
.replace(/[^\da-fA-F]/g, ''),
type: imageType
})
}
}
}
return result
},
// 将 hex 数据转换为 Uint8Array:首先需要将 hex 字符串转换成 Uint8Array
hexToUint8Array(hex) {
// 将 hex 字符串转换为一个字节数组
const byteArray = new Uint8Array(hex.length / 2)
for (let i = 0; i < hex.length; i += 2) {
byteArray[i / 2] = parseInt(hex.substr(i, 2), 16)
}
return byteArray
},
// 上传图片
uploadAllImage(item) {
if (item.hex && item.type) {
return new Promise((resolve, reject) => {
// 将 hex 数据转换为 Uint8Array
const byteArray = this.hexToUint8Array(item.hex)
// 创建一个 Blob 对象
const blob = new Blob([byteArray], { type: item.type })
// 创建 FormData 对象
const formData = new FormData()
formData.append('isPublic', true) // 是否公开,根据需求决定
formData.append('file', blob) // 将 Blob 添加到表单数据中,指定文件名
// 调用上传函数(假设使用 uploadFile 函数)
uploadFile(formData).then(res => {
console.log('上传成功:', res)
resolve(res.downloadUrl)
}).catch(error => {
console.error('上传失败:', error)
reject()
})
})
}
}
}
})
</script>
<style src="@wangeditor/editor/dist/css/style.cs

小白前端~
- 粉丝: 1
最新资源
- 网络安全(PPT36页)(1).ppt
- 论借助sniffer诊断Linux网络故障.docx
- 商务英语教学中网络的地位.doc
- 在市打击治理电信网络新型违法犯罪联席会议上表态发言三篇.doc
- 2023年大学计算机基础期末考试知识点.doc
- 系统安全预测技术.pptx
- 企业信息化建设的重要性和状况.docx
- 遥感数字图像处理考题整理.doc
- 高校师生同上一堂网络安全课观后感心得感悟5篇.docx
- 企业集团财务结算中心与计算机系统设计与会计操作.doc
- 电话网络系统方案.doc
- 九上下册物理第三节:广播-电视和移动通信公开课教案教学设计课件测试卷练习卷课时同步训练练习公开课教案.ppt
- 图像处理:十一表示描述.ppt
- 什么网站工作总结写的比较好.docx
- 项目管理与招标采购培训重点课程.doc
- 有关信息化银行对账问题的探讨【会计实务操作教程】.pptx
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈


