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  //试剂的保存与使用
				},
			}
		}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/871545.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

「字符串」前缀函数|KMP匹配:规范化next数组 / LeetCode 28(C++)

目录 概述 思路 核心概念&#xff1a;前缀函数 1.前缀函数 2.next数组 1.考研版本 2.竞赛版本 算法过程 构建next数组 匹配过程 复杂度 Code 概述 为什么大家总觉得KMP难&#xff1f;难的根本就不是这个算法本身。 在互联网上你可以见到八十种KMP算法的next数组…

SQL 布尔盲注 (injection 第六关)

简介 SQL注入&#xff08;SQL Injection&#xff09;是一种常见的网络攻击方式&#xff0c;通过向SQL查询中插入恶意的SQL代码&#xff0c;攻击者可以操控数据库&#xff0c;SQL注入是一种代码注入攻击&#xff0c;其中攻击者将恶意的SQL代码插入到应用程序的输入字段中&am…

26.删除有序数组中的重复项---力扣

题目链接&#xff1a; . - 力扣&#xff08;LeetCode&#xff09;. - 备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/remove-duplicates-from-sorted-array/descript…

嵌入式学习——(Linux高级编程——线程)

线程 一、pthread 线程概述 pthread&#xff08;POSIX threads&#xff09;是一种用于在程序中实现多线程的编程接口。它与进程一样&#xff0c;可以用于实现并发执行任务&#xff0c;但与进程相比有一些不同的特点。 二、优点 1. 比多进程节省资源&#xff1a;进程在创建时…

PDPS软件 那智机器人 (丰田版)离线程序导出处理

在PDPS仿真软件中导出的那智机器人离线程序&#xff0c;一般是无法直接给TFD控制装置-那智机器人&#xff08;丰田式样版&#xff09;导入及识别使用。因此要对导出的程序进行转换编译处理&#xff0c;才能给TFD那智机器人&#xff08;丰田式样版&#xff09;导入离线程序。以下…

HarmonyOS 开发

环境 下载IDE 代码 import { hilog } from kit.PerformanceAnalysisKit; import testNapi from libentry.so; import { router } from kit.ArkUI; import { common, Want } from kit.AbilityKit;Entry Component struct Index {State message: string Hello HarmonyOS!;p…

类与对象(中(2))

开头 大家好啊&#xff0c;上一期内容我们介绍了类与对象中六大默认成员函数中的两种--->构造函数与析构函数&#xff0c;相信大家多少都形成了自己的独到见解。那么今天&#xff0c;我将继续就拷贝构造函数与运算符重载函数来展开讲解&#xff0c;话不多说&#xff0c;我们…

Python版《超级玛丽+源码》-Python制作超级玛丽游戏

小时候最喜欢玩的小游戏就是超级玛丽了&#xff0c;有刺激有又技巧&#xff0c;通关真的很难&#xff0c;救下小公主还被抓走了&#xff0c;唉&#xff0c;心累&#xff0c;最后还是硬着头皮继续闯&#xff0c;终于要通关了&#xff0c;之后再玩还是没有那么容易&#xff0c;哈…

十五年以来 — 战略性云平台服务的演进路径之全面呈现(含亚马逊、微软和谷歌)

Gartner每年都发布对全球IaaS平台进行评估的魔力象限报告。2023年底&#xff0c;Gartner将此项评估的名称改为“战略性云平台服务”&#xff08;Strategic cloud platform services&#xff09;&#xff0c;尽管其核心仍为IaaS&#xff0c;但是&#xff0c;毫无疑问&#xff0c…

手机云电脑游戏测评:ToDesk、易腾云、达龙云、青椒云四款对比分析

文章目录 &#x1f4d1; 引言一、背景概述测试目标 二、测试方案与评测标准2.1 测试设备2.2 评测标准 三、云电脑移动端实测3.1 ToDesk云电脑3.1.1 安装步骤与用户界面3.1.2 性能测试3.1.3 多场景适用性与兼容性3.1.4 性价比 3.2 易腾云电脑3.2.1 安装流程与用户界面3.2.2 帧率…

WebRTC为何成为视频开发领域的首选技术? EasyCVR视频转码助力无缝视频通信

随着互联网的飞速发展&#xff0c;视频通信已成为日常生活和工作中不可或缺的一部分。从在线教育、视频会议到远程医疗、在线直播&#xff0c;视频开发的需求日益增长。在这些应用场景中&#xff0c;选择何种技术来构建视频系统至关重要。 目前&#xff0c;在很多视频业务的开…

Golang | Leetcode Golang题解之第352题将数据流变为多个不相交区间

题目&#xff1a; 题解&#xff1a; type SummaryRanges struct {*redblacktree.Tree }func Constructor() SummaryRanges {return SummaryRanges{redblacktree.NewWithIntComparator()} }func (ranges *SummaryRanges) AddNum(val int) {// 找到 l0 最大的且满足 l0 < val…

Browserless 网页抓取:Playwright 中的 NodeJS

什么是 Playwright&#xff1f; Playwright 是一个用于 Web 测试和自动化的开源框架。基于 Node.js&#xff0c;由 Microsoft 开发&#xff0c;它通过单一 API 支持 Chromium、Firefox 和 WebKit。它可以在 Windows、Linux 和 macOS 上运行&#xff0c;并且兼容 TypeScript、J…

设计模式六大原则(一)--单一职责原则

摘要 单一职责原则是设计模式六大原则之一&#xff0c;强调一个类应该仅有一个引起它变化的原因&#xff0c;即每个类应仅负责一项职责。本文通过详细探讨单一职责原则的定义、实现方式、优缺点及其适用场景&#xff0c;揭示了其在软件设计中的核心地位。通过类的拆分、接口设…

TCP协议段中的六个标志位

目录 ACK SYN RST FIN PSH URG TCP报文格式中的六个标志位由6个比特构成&#xff0c;在通信双方基于TCP协议互相发送报文数据时可以通过报头中标志位来区别对方发送的报文数据的请示。 ACK 确认号是否有效。 接收端对所收到的报文进行检查&#xff0c;若未发现错误&…

周易测算系统开发:融合古典智慧与现代技术的创新实践

一、引言 周易&#xff0c;作为中国古代文化的瑰宝&#xff0c;蕴含着深邃的哲学思想与预测智慧&#xff0c;其独特的六十四卦体系及爻变原理&#xff0c;自古以来便被人们用于探索自然规律、人生哲理及未来趋势。随着科技的飞速发展&#xff0c;将周易智慧与现代计算机技术相结…

StackStorm自动化平台

1. StackStorm概述 1.1 StackStorm介绍 StackStorm是一个开源的事件驱动自动化平台&#xff0c;它允许开发者和系统管理员自动化IT和网络操作。StackStorm结合了IT运维、DevOps和网络安全团队的需求&#xff0c;提供了一个集中式的工作流自动化解决方案&#xff0c;包括事件响…

图像数据处理13

三、空域滤波 3.1滤波器的基本概念 什么是滤波&#xff1f; 简单来说就是从干扰信号中提取出有用的信号 3.1.1空域滤波&#xff08;Spatial Domain Filtering&#xff09; 空域滤波适用于简单的滤波任务&#xff0c;直接对图像的像素空间进行操作。它通过对图像中的每个像…

ES 支持乐观锁吗?如何实现的?

本篇主要介绍一下Elasticsearch的并发控制和乐观锁的实现原理&#xff0c;列举常见的电商场景&#xff0c;关系型数据库的并发控制、ES的并发控制实践。 并发场景 不论是关系型数据库的应用&#xff0c;还是使用Elasticsearch做搜索加速的场景&#xff0c;只要有数据更新&…