vue 富文本编辑器 wangeditor 自定义上传图片 以及 解决 复制粘贴 word 没有图片的情况
本人比较喜欢用这一款编辑器,官方文档:(用于 Vue React | wangEditor),很详细。我主要来说说怎么使用customPaste
自定义粘贴的,怎么解决 复制粘贴 word ,没有图片的情况。
主要是关于wangeditor在vue2的使用
效果图:
先把完整代码放这里:
<template>
<div class="addpost_course">
<div id="editor" style="border: 1px solid #ccc; width: 534px">
<Toolbar
style="border-bottom: 1px solid #ccc"
:editor="editor"
:defaultConfig="toolbarConfig"
:mode="mode"
/>
<Editor
style="height: 200px; overflow-y: hidden"
v-model="content"
:defaultConfig="editorConfig"
:mode="mode"
@onCreated="onCreated"
@onChange="onChange"
@onDestroyed="onDestroyed"
@onMaxLength="onMaxLength"
@onFocus="onFocus"
@onBlur="onBlur"
@customAlert="customAlert"
@customPaste="customPaste"
/>
</div>
</div>
</template>
<script>
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import { Loading, Message } from "element-ui";
export default {
components: { Editor, Toolbar },
data() {
return {
// 富文本
editor: null,
// 富文本里面的所有内容(带标签的)
content: "",
toolbarConfig: {},
editorConfig: {
placeholder: "请输入内容...",
// 所有的菜单配置,都要在 MENU_CONF 属性下
MENU_CONF: {
//配置上传图片
uploadImage: {
// 自定义上传图片 方法
customUpload: this.uploadImg,
// 自定义插入图片 方法
customInsert: this.insertImg,
//server必须要配置正确,我这里因为上传图片有点特殊,在下面方法配置了,所以此处不用配置地址
// server: 'https://xwbdzzz.haiyan.gov.cn:10002/form/temp/update/ajax/img',
maxFileSize: 4 * 1024 * 1024, // 1M
// 最多可上传几个文件,默认为 100
maxNumberOfFiles: 100,
// 选择文件时的类型限制,默认为 ['image/*'] 。如不想限制,则设置为 []
allowedFileTypes: [],
// 自定义上传参数,例如传递验证的 token 等。参数会被添加到 formData 中,一起上传到服务端。
fieldName: "file",
meta: {
//官网中把token放到了这里,但是请求的时候会看不到token
},
headers: {
//所以token放这里
// token: window.sessionStorage.token,
},
// 将 meta 拼接到 url 参数中,默认 false
metaWithUrl: false,
// 跨域是否传递 cookie ,默认为 false
withCredentials: false,
// 超时时间,默认为 10 秒
timeout: 5 * 1000, // 5 秒
// 上传之前触发
// onBeforeUpload(file) {
// console.log(file); // JS 语法
// // file 选中的文件,格式如 { key: file }
// return file
// // 可以 return
// // 1. return file 或者 new 一个 file ,接下来将上传
// // 2. return false ,不上传这个 file
// },
// // 上传进度的回调函数
// onProgress(progress) { // JS 语法
// // progress 是 0-100 的数字
// console.log('progress', progress)
// },
// // 单个文件上传成功之后
// onSuccess(file, res) { // JS 语法
// console.log(`${file.name} 上传成功`, res)
// },
// // 单个文件上传失败
// onFailed(file, res) { // JS 语法
// console.log(`${file.name} 上传失败`, res)
// },
// // 上传错误,或者触发 timeout 超时
// onError(file, err, res) { // JS 语法
// console.log(`${file.name} 上传出错`, err, res)
// },
},
// 配置上传视频(同上传图片)
uploadVideo: {},
},
},
mode: "default", // or 'simple'
methods: {
// 富文本
onCreated(editor) {
this.editor = Object.seal(editor); // 一定要用 Object.seal() ,否则会报错
console.log(this.editor);
},
onChange(editor) {
console.log("onChange", editor.children, this.content);
},
onDestroyed(editor) {
console.log("onDestroyed", editor);
},
onMaxLength(editor) {
console.log("onMaxLength", editor);
},
onFocus(editor) {
console.log("onFocus", editor);
},
onBlur(editor) {
console.log("onBlur", editor);
},
customAlert(info, type) {
window.alert(`customAlert in Vue demo\n${type}:\n${info}`);
},
//重点来了: 自定义粘贴。可阻止编辑器的默认粘贴,实现自己的粘贴逻辑。(可以实现复制粘贴 word ,有图片)
customPaste(editor, event, callback) {
console.log("ClipboardEvent 粘贴事件对象", event);
let html = event.clipboardData.getData("text/html"); // 获取粘贴的 html
// let text = event.clipboardData.getData('text/plain') // 获取粘贴的纯文本
let 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:此处可以将图片上传到自己的服务器上
// 执行替换:将html内容中的img标签的src替换成ref中的图片数据,如果上面上传了则为图片路径
html = that.replaceImagesFileSourceWithInlineRepresentation(
html,
imgSrcs,
rtfImageData
);
editor.dangerouslyInsertHtml(html);
}
}
// 阻止默认的粘贴行为
event.preventDefault();
return false;
} else {
return true;
}
},
//自定义上传图片
uploadImg(file, insertFn) {
let imgData = new FormData();
console.log(file);
imgData.append("file", file);
//调用上传图片接口,上传图片
this.$api.post("/form/temp/update/ajax/img", imgData).then((res) => {
console.log(res);
// 插入后端返回的url
insertFn(res[0].url);
this.$message({
type: "success",
message: "上传成功",
});
})
.catch((error) => {
this.$message("上传失败,请重新上传");
});
},
// 自定义插入图片
insertImg(file) {
console.log(file);
},
/**
* 从html代码中匹配返回图片标签img的属性src的值的集合
* @param htmlData
* @return Array
*/
findAllImgSrcsFromHtml(htmlData) {
let imgReg = /<img.*?(?:>|\/>)/gi; //匹配图片中的img标签
let srcReg = /src=[\'\"]?([^\'\"]*)[\'\"]?/i; // 匹配图片中的src
let arr = htmlData.match(imgReg); //筛选出所有的img
if (!arr || (Array.isArray(arr) && !arr.length)) {
return false;
}
let srcArr = [];
for (let i = 0; i < arr.length; i++) {
let 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;
},
/**
* 将html内容中img标签的属性值替换
* @param htmlData html内容
* @param imageSrcs html中img的属性src的值的集合
* @param imagesHexSources rtf中图片数据的集合,与html内容中的img标签对应
* @param isBase64Data 是否是Base64的图片数据
* @return String
*/
replaceImagesFileSourceWithInlineRepresentation(
htmlData,
imageSrcs,
imagesHexSources,
isBase64Data = true
) {
if (imageSrcs.length === imagesHexSources.length) {
for (let i = 0; i < imageSrcs.length; i++) {
const newSrc = isBase64Data
? `data:${
imagesHexSources[i].type
};base64,${this._convertHexToBase64(imagesHexSources[i].hex)}`
: imagesHexSources[i];
htmlData = htmlData.replace(imageSrcs[i], newSrc);
}
}
return htmlData;
},
/**
* 十六进制转base64
*/
_convertHexToBase64(hexString) {
return btoa(
hexString
.match(/\w{2}/g)
.map((char) => {
return String.fromCharCode(parseInt(char, 16));
})
.join("")
);
},
// 销毁富文本
beforeDestroy() {
const editor = this.editor;
if (editor == null) return;
editor.destroy(); // 组件销毁时,及时销毁编辑器
},
};
</script>
//记得引入wangeditor样式
<style src="@wangeditor/editor/dist/css/style.css"></style>
<style lang='scss' scoped>
@import "../mystyle/addpost_course";
</style>
上传图片我这里有点特殊,就不细说了
自定义粘贴:就几点:
-
实现方法:通过 wangEditor 的编辑器配置 API 中的 customPaste 自定义粘贴
-
实现步骤: 注意获取粘贴的 html和获取 rtf 数据 ,用let,不能用const,下面会发生修改 -特别注意:允许默认粘贴行为 既可以复制图片,也可以复制文本,还可以图片文本;阻止默认的粘贴行为,只能粘贴复制文字带图片的文本
// 自定义粘贴。可阻止编辑器的默认粘贴,实现自己的粘贴逻辑。(可以实现复制粘贴 word ,有图片)
customPaste(editor, event, callback) {
console.log("ClipboardEvent 粘贴事件对象", event);
let html = event.clipboardData.getData("text/html"); // 获取粘贴的 html,
// let text = event.clipboardData.getData('text/plain') // 获取粘贴的纯文本
let rtf = event.clipboardData.getData("text/rtf"); // 获取 rtf 数据(如从 word wsp 复制粘贴)
var that = this;
if (html && rtf) {
// 该条件分支即表示要自定义word粘贴
// 列表缩进会超出边框,直接过滤掉
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:此处可以将图片上传到自己的服务器上
// 执行替换:将html内容中的img标签的src替换成ref中的图片数据,如果上面上传了则为图片路径
html = that.replaceImagesFileSourceWithInlineRepresentation(
html,
imgSrcs,
rtfImageData
);
editor.dangerouslyInsertHtml(html);
}
}
// 阻止默认的粘贴行为 //此处非常关键 允许默认行为 既可以复制图片,也可以复制文本,还可以图片文本
// event.preventDefault();
//event.preventDefault();
return false;
} else {
return true;
}
},
- 以上实现步骤涉及到几个方法:
javascript
复制代码
/**
* 从html代码中匹配返回图片标签img的属性src的值的集合
* @param htmlData
* @return Array
*/
findAllImgSrcsFromHtml(htmlData) {
let imgReg = /<img.*?(?:>|\/>)/gi; //匹配图片中的img标签
let srcReg = /src=[\'\"]?([^\'\"]*)[\'\"]?/i; // 匹配图片中的src
let arr = htmlData.match(imgReg); //筛选出所有的img
if (!arr || (Array.isArray(arr) && !arr.length)) {
return false;
}
let srcArr = [];
for (let i = 0; i < arr.length; i++) {
let 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;
}
/** * 将html内容中img标签的属性值替换 * @param htmlData html内容 * @param imageSrcs html中img的属性src的值的集合 * @param imagesHexSources rtf中图片数据的集合,与html内容中的img标签对应 * @param isBase64Data 是否是Base64的图片数据 * @return String */ replaceImagesFileSourceWithInlineRepresentation( htmlData, imageSrcs, imagesHexSources, isBase64Data = true ) {
if (imageSrcs.length === imagesHexSources.length) {
for (let i = 0; i < imageSrcs.length; i++) {
const newSrc = isBase64Data ? `data:${ imagesHexSources[i].type };base64,${this._convertHexToBase64(imagesHexSources[i].hex)}` : imagesHexSources[i]; htmlData = htmlData.replace(imageSrcs[i], newSrc);
}
}
return htmlData;
},
/** * 十六进制转base64 */ _
convertHexToBase64(hexString) {
return btoa( hexString .match(/\w{2}/g) .map((char) => { return String.fromCharCode(parseInt(char, 16)); }) .join("") ); },
原理:可以去看看他的文章,不错 ( wangEditor 粘贴从 word 复制的带图片内容的最佳实践_ wangeditor粘贴word图片https://blog.csdn.net/assokoo123/article/details/126034566 wangEditor 粘贴从 word 复制的带图片内容的最佳实践_ wangeditor粘贴word图片)