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  //试剂的保存与使用
				},
			}
		}
相关推荐
贩卖纯净水.2 分钟前
Chrome调试工具(查看CSS属性)
前端·chrome
栈老师不回家1 小时前
Vue 计算属性和监听器
前端·javascript·vue.js
前端啊龙1 小时前
用vue3封装丶高仿element-plus里面的日期联级选择器,日期选择器
前端·javascript·vue.js
一颗松鼠1 小时前
JavaScript 闭包是什么?简单到看完就理解!
开发语言·前端·javascript·ecmascript
小远yyds1 小时前
前端Web用户 token 持久化
开发语言·前端·javascript·vue.js
程序媛小果2 小时前
基于java+SpringBoot+Vue的宠物咖啡馆平台设计与实现
java·vue.js·spring boot
小光学长2 小时前
基于vue框架的的流浪宠物救助系统25128(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。
数据库·vue.js·宠物
阿伟来咯~2 小时前
记录学习react的一些内容
javascript·学习·react.js
吕彬-前端2 小时前
使用vite+react+ts+Ant Design开发后台管理项目(五)
前端·javascript·react.js
学前端的小朱2 小时前
Redux的简介及其在React中的应用
前端·javascript·react.js·redux·store