vue+ckEditor5 复制粘贴wold文字+图片并保存格式

第一步在vue2项目下安装

npm install --save @ckeditor/ckeditor5-build-decoupled-document  

第二 项目下新建一个plugins的文件夹将这个包ckeditor5-build-classic放入

(包在页面最上方 有个下载按钮 可以下载)

刚开始时 ckeditor5-build-classic文件夹下无node_modules,需要找到 项目下的ruoyi-ui\src\plugins\ckeditor5-build-classic文件地址,cmd打开,然后输入npm install 安装下 ckeditor5-build-classic文件夹下就有这个了node_modules

第三步 (为了兼容wold和pdf的粘贴)

找到plugins\ckeditor5-build-classic\node_modules@ckeditor\ckeditor5-paste-from-office\src\filters\image.js 这个文件,然后打开,搜索regexPictureHeader,将某段代码进行替换如下

//图片替换
regexPictureHeader = /{\pict[\s\S]+?({\*\blipuid\s?[\da-fA-F]+})+?/;

第四步 (为了兼容wold和pdf的粘贴)

找到plugins\ckeditor5-build-classic\node_modules@ckeditor\ckeditor5-paste-from-office\src\filters\space.js 这个文件 ,然后打开,搜索htmlDocument.querySelectorAll,将这段代码替换如下

htmlDocument.querySelectorAll('span[style*=spacerun]').forEach(el => {
 if (/[^\b]/.test(el.innerText.trim()) === false) {
 const innerTextLength = el.innerText.length || 0;
 el.innerHTML = Array(innerTextLength + 1).join('\u00A0 ').substr(0, innerTextLength);
 }
 });

第五步 在api文件下新建upload.js

import { getToken } from "@/utils/auth";
// upload.js中
class MyUploadAdapter {
  constructor(loader) {
    // 要在上载期间使用的文件加载器实例
    this.loader = loader;
  }

  // 启动上载过程
  upload() {
    return this.loader.file.then(
      (file) =>
        new Promise((resolve, reject) => {
          this._initRequest();
          this._initListeners(resolve, reject, file);
          this._sendRequest(file);
        })
    );
  }

  // 中止上载过程
  abort() {
    if (this.xhr) {
      this.xhr.abort();
    }
  }

  // 使用传递给构造函数的URL初始化XMLHttpRequest对象.
  _initRequest() {
    const xhr = (this.xhr = new XMLHttpRequest());
    // 后端上传图片接口     `${process.env.VUE_APP_BASE_API}/common/upload`,
    xhr.open(
      "POST",
      `${process.env.VUE_APP_BASE_API}/common/upload`,
      true
    );
    xhr.responseType = "json";
  }

  // 初始化 XMLHttpRequest 监听.
  _initListeners(resolve, reject, file) {
    const xhr = this.xhr;
    const loader = this.loader;
    const genericErrorText = `无法上传文件: ${file.name}.`;

    xhr.addEventListener("error", () => reject(genericErrorText));
    xhr.addEventListener("abort", () => reject());
    xhr.addEventListener("load", () => {
      //这个例子假设XHR服务器的"response"对象将附带
      //一个"error",它有自己的"message",可以传递给reject()
      //你的集成可能以不同的方式处理上传错误,所以请确保
      //当上传失败时,必须调用reject()函数。
      const response = xhr.response;
      // 当上传失败时,必须调用reject()函数。
      if (!response || response.error) {
        // reject方法会调用浏览器的alert事件 并清除页面上的图片展示
        return reject(
          response && response.error
            ? response.error.message
            : genericErrorText
        );
      }
      // 上传成功,从后台获取图片的url地址
      // resolve方法会将default中的值插入到页面中img标签的src中
      resolve({
        default: response.url,
      });
    });

    // 支持时上传进度。文件加载器有#uploadTotal和#upload属性,用于在编辑器用户界面中显示上载进度栏。
    if (xhr.upload) {
      xhr.upload.addEventListener("progress", (evt) => {
        if (evt.lengthComputable) {
          loader.uploadTotal = evt.total;
          loader.uploaded = evt.loaded;
        }
      });
    }
  }

  // 准备数据并发送请求
  _sendRequest(file) {
    // 通过FormData构造函数创建一个空对象
    const data = new FormData();
    // 通过append()方法在末尾追加key为files值为file的数据
    data.append("file", file); // 上传的参数data
    /**
     * 重要提示:这是实现诸如身份验证和CSRF保护等安全机制的正确位置。
     * 例如,可以使用XMLHttpRequest.setRequestHeader()设置包含应用程序先前生成的CSRF令牌的请求头。
     */
    this.xhr.setRequestHeader("Authorization", getToken());
    this.xhr.send(data);
  }
}

function MyCustomUploadAdapterPlugin(editor) {
  editor.plugins.get('FileRepository').createUploadAdapter = (loader) => {
    // 在这里将URL配置为后端上载脚本
    return new MyUploadAdapter(loader)
  }
}

export {
  MyUploadAdapter,
  MyCustomUploadAdapterPlugin
}

第六步

组件页面 components/CkEditor/index.vue

<template>
	<div>
		<div :id="editorID"></div>
	</div>
</template>

<script>
	import {
		MyCustomUploadAdapterPlugin,
		MyUploadAdapter
	} from "@/api/upload";
	import ClassicEditor from "@/plugins/ckeditor5-build-classic";
	import "@/plugins/ckeditor5-build-classic/build/translations/zh-cn.js";
	export default {
		props: {
			/* 编辑器的内容 */
			ckEditorValue: {
				type: String,
				default: "",
			},
			/* 只读模式 */
			readOnly: {
				type: Boolean,
				default: false,
			},
			/* 控制什么时候显示工具条 */
			inEditorShow: {
				type: Boolean,
				default: true,
			},
			/* editorID */
			editorID: {
				type: String,
				default: 'editor',
			}
		},
		data() {
			return {
				editor: ''
			}
		},
		watch: {
			ckEditorValue: {
				handler(newVal) {
					var that = this;
					setTimeout(() => {
						if (that.editor != '' && that.editor != null && that.editor != undefined)
							that.editor.setData(that.ckEditorValue);
					}, 100)
				},
				immediate: true,
				deep: true
			},
			readOnly: {
				handler(newVal) {
					var that = this;
					setTimeout(() => {
						if (newVal) {
							if (that.editor != '' && that.editor != null && that.editor != undefined)
								that.editor.enableReadOnlyMode('editor');
						} else {
							if (that.editor != '' && that.editor != null && that.editor != undefined)
								that.editor.disableReadOnlyMode('editor');
						}
					}, 100)
				},
				immediate: true,
				deep: true
			}
		},
		mounted() {
			this.initEditor();
		},
		methods: {
			initEditor() {
				let that = this;
				ClassicEditor.create(document.querySelector(`#${that.editorID}`), {
						language: 'zh-cn',
						extraPlugins: [MyCustomUploadAdapterPlugin],
						placeholder: '请输入内容....',
						autosave: {
							waitingTime: 100,
							save(editor) {
								// return that.saveData(editor.getData());
								sessionStorage.setItem("saveEditorData", editor.getData());
							},
						}
					})
					.then((editor) => {
						// 设置富文本高度
						editor.editing.view.change(writer => {
							writer.setStyle('min-height', '500px', editor.editing.view.document.getRoot());
						});
						// 上传文件
						editor.plugins.get("FileRepository").createUploadAdapter = (
							loader
						) => {
							return new MyUploadAdapter(loader);
						};
						//富文本是否只读
						if (this.readOnly) {
							editor.enableReadOnlyMode('editor');
						} else {
							editor.disableReadOnlyMode('editor');
						}
						//根据父组件判断是否显示工具栏
						if (!this.inEditorShow) {
							var toolbar = document.getElementsByClassName('ck-toolbar');
							var border = document.getElementsByClassName('ck-editor__editable_inline');
							toolbar[0].style.display = 'none';
							border[0].style.border = 'none';
						}
						editor.setData(that.ckEditorValue);
						that.editor = editor;
					})
					.catch((error) => console.error(error));
			},
			clear() {
				this.editor.setData('');
			}
		}
	}
</script>

<style>
	.ck-body-wrapper {
		position: absolute;
		z-index: 3000;
	}

	.ck a {
		color: rgb(24, 144, 255);
	}
</style>

<style lang="scss" scoped>
</style>

第七步 页面引用

<template>
	 <CkEditor :ckEditorValue="dataForm.storageAndUse"   @saveEditorData="saveEditorData"></CkEditor>
</template>
<script>
	import CkEditor from "../components/CkEditor/index.vue";
	export default {
		components:{CkEditor},
		data() {
			return {
			dataForm: {
					id: null,
					storageAndUse: null  //试剂的保存与使用
				},
			}
		}
相关推荐
如若12329 分钟前
对文件内的文件名生成目录,方便查阅
java·前端·python
滚雪球~1 小时前
npm error code ETIMEDOUT
前端·npm·node.js
沙漏无语1 小时前
npm : 无法加载文件 D:\Nodejs\node_global\npm.ps1,因为在此系统上禁止运行脚本
前端·npm·node.js
supermapsupport1 小时前
iClient3D for Cesium在Vue中快速实现场景卷帘
前端·vue.js·3d·cesium·supermap
brrdg_sefg1 小时前
WEB 漏洞 - 文件包含漏洞深度解析
前端·网络·安全
胡西风_foxww1 小时前
【es6复习笔记】rest参数(7)
前端·笔记·es6·参数·rest
m0_748254881 小时前
vue+elementui实现下拉表格多选+搜索+分页+回显+全选2.0
前端·vue.js·elementui
星就前端叭2 小时前
【开源】一款基于Vue3 + WebRTC + Node + SRS + FFmpeg搭建的直播间项目
前端·后端·开源·webrtc
m0_748234522 小时前
前端Vue3字体优化三部曲(webFont、font-spider、spa-font-spider-webpack-plugin)
前端·webpack·node.js
Web阿成2 小时前
3.学习webpack配置 尝试打包ts文件
前端·学习·webpack·typescript