自定义自定义Vue-Quill-Editor富文本框可参照:
https://blog.csdn.net/ccsundhine/article/details/125867053?spm=1001.2014.3001.5502
注意:

  • 秀米官网声明只支持ueditor内核的编辑器内核(本文使用quill富文本框,自定义了一个blot文件,防止quill自动过滤掉秀米和135编辑器里面的section之类的样式)
  • 秀米的第三方对接文档地址:https://ent.xiumi.us/doc2.html
  • 您的网站务必使用https访问,否则会造成用户无法登录秀米账户
  • 秀米官方更新后,在本地开发环境时,无法正常插入数据到编辑器;且在ip环境下无法登录秀米
  • 秀米插入编辑器前需要做图片本地化处理才能正常显示(如果不处理图片就会裂开,上传的图片是存放在秀米的服务器上面的,这样会消耗秀米的服务器资源,所以秀米会禁止外站的图片请求)可以考虑两种方式:quill自定义处理粘贴的文本内容;在index.html通过通过referrer去处理;
  • 秀米以及135编辑器回显的时候,如果有section之类的元素也会被过滤,所以在回显数据的时候也需要处理

  1. 把秀米编辑器和135编辑器的html文件放入public文件下(秀米这里有两个文件一个新版一个旧版本,自愿引入哪一个)

    135EditorDialogPage.html文件:
<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>135编辑器</title><style>html,body {padding: 0;margin: 0;}#editor135 {position: absolute;width: 100%;height: 100%;border: none;box-sizing: border-box;}</style>
</head><body><iframe id="editor135" src="//www.135editor.com/simple_editor.html?callback=true&appkey="></iframe><!-- <script type="text/javascript" src="internal.js"></script> --><script>var editor135 = document.getElementById('editor135');var parent = window.parent;window.onload = function () {setTimeout(function () {editor135.contentWindow.postMessage(parent.getHtml(), '*');// parent.getHtml 其实是quill里暴露的 window.getHtml}, 3000);};document.addEventListener("mousewheel", function (event) {event.preventDefault();event.stopPropagation();});window.addEventListener('message', function (event) {if (typeof event.data !== 'string') return;parent.setRichText_135(event.data)// editor.setContent(event.data);// editor.fireEvent("catchRemoteImage"); // dialog.close();}, false);</script>
</body></html>

xiumi-ue-dialog-v5_new.html文件:

<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>XIUMI connect</title><style>html,body {padding: 0;margin: 0;}#xiumi {position: absolute;width: 100%;height: 100%;border: none;box-sizing: border-box;}</style>
</head><body><iframe id="xiumi" src="//xiumi.us/studio/v5#/paper"></iframe><!-- <script type="text/javascript" src="dialogs/internal.js"></script> --><script>var parent = window.parent;console.log('parent: ', parent);var xiumi = document.getElementById('xiumi');var xiumi_url = window.location.protocol + "//xiumi.us";console.log("xiumi_url is %o", xiumi_url);xiumi.onload = function () {console.log("postMessage to %o", xiumi_url);// "XIUMI:3rdEditor:Connect" 是特定标识符,不能修改,大小写敏感xiumi.contentWindow.postMessage('XIUMI:3rdEditor:Connect', xiumi_url);};document.addEventListener("mousewheel", function (event) {event.preventDefault();event.stopPropagation();});window.addEventListener('message', function (event) {console.log("Received message from xiumi, origin: %o %o", event.origin, xiumi_url);console.log('event.data: ', event.data);if (event.origin == xiumi_url) {console.log("Inserting html");parent.setRichText_xm(event.data)console.log("Xiumi dialog is closing");// dialog.close();}}, false);</script>
</body></html>

xiumi-ue-dialog-v5.html文件:

<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>XIUMI connect</title><style>html,body {padding: 0;margin: 0;}#xiumi {position: absolute;width: 100%;height: 100%;border: none;box-sizing: border-box;}</style>
</head><body><iframe id="xiumi" src="//xiumi.us/studio/v5#/paper"></iframe><!-- <script type="text/javascript" src="internal.js"></script> --><script>var parent = window.parent;var xiumi = document.getElementById('xiumi');var xiumi_url = window.location.protocol + "//xiumi.us";xiumi.onload = function () {console.log("postMessage");xiumi.contentWindow.postMessage('ready', xiumi_url);};document.addEventListener("mousewheel", function (event) {event.preventDefault();event.stopPropagation();});window.addEventListener('message', function (event) {if (event.origin == xiumi_url) {parent.setRichText_xm(event.data)// editor.execCommand('insertHtml', event.data);// dialog.close();}}, false);</script>
</body></html>
  1. 用iframe引入(这里踩了一个坑!!!!src引入文件的时候一定要看清楚自己项目的publicPath )
<div  :style="{ height: fullheight + 'px' }"><!-- quill --><quill-editorref="myQuillEditor"v-model="articleForm.artContent"v-screenclass="quilleditor":options="editorOption"style="height: 265px"/><el-dialog:append-to-body="true":close-on-click-modal="false":modal-append-to-body="false"title="秀米"top="50px":visible.sync="visible"width="90%"z-index="99999999"><!-- 秀米插件弹框 --><div v-if="visible"><!-- :src="`${baseUrl}static/xiumi-ue-dialog-v5_new.html?time=1267765432`" --><iframeid="xiumiIframe"frameborder="0":height="fullheight - 150 + 'px'"src="./static/xiumi-ue-dialog-v5_new.html"width="100%"></iframe></div></el-dialog> <!-- 135编辑器弹框 --><el-dialog:append-to-body="true":close-on-click-modal="false":modal-append-to-body="false"title="135编辑器"top="50px":visible.sync="visible2"width="90%"z-index="99999999"><div v-if="visible2"><iframeid="xiumiIframe"frameborder="0":height="fullheight - 150 + 'px'"src="./static/135EditorDialogPage.html"width="100%"></iframe></div></el-dialog></div>
  1. 自定义blot.js文件(防止quill过滤)
export default function (Quill) {// 引入源码中的BlockEmbedconst BlockEmbed = Quill.import('blots/block/embed');// 定义新的blot类型class AppPanelEmbed extends BlockEmbed {static create(value) {const node = super.create(value);// node.setAttribute('contenteditable', 'false');// node.setAttribute('width', '100%');//   设置自定义htmlnode.innerHTML = this.transformValue(value)// 返回firstChild,避免被包一层<div class='rich-innerHtml'></div>的无意义标签return node.firstChild;}static transformValue(value) {let handleArr = value.split('\n')handleArr = handleArr.map(e => e.replace(/^[\s]+/, '').replace(/[\s]+$/, ''))return handleArr.join('')}// 返回节点自身的value值 用于撤销操作static value(node) {return node.innerHTML}}// blotNameAppPanelEmbed.blotName = 'AppPanelEmbed';// class名将用于匹配blot名称AppPanelEmbed.className = 'rich-innerHtml';// 标签类型自定义,这玩意还必须加,去掉会报错AppPanelEmbed.tagName = 'div';Quill.register(AppPanelEmbed, true);
}
  1. 在js中使用 (引入blot文件,配置quill等)
<script>// 秀米引入import blotSelect from './components/blot.js'blotSelect(Quill)// 工具栏配置(可根据自己的需求配置quill工具栏)const toolbarOptions = [['insertMetric'], //秀米['otEdit'], //135编辑器]export default {data() {return {msg: undefined,imgFile: undefined,//富文本内容articleForm:{artContent:""},visible: false,//秀米visible2: false,135编辑器selection: {}, // 光标位置fullheight: document.documentElement.clientHeight, // 给quill容器设置了个高度quill: null, // 待初始化的编辑器//quill配置editorOption: {modules: {toolbar: {container: toolbarOptions, //自定义工具栏handlers: {that: this,// 秀米insertMetric: function () {let self = this.handlers.thatself.visible = true},// 135编辑器otEdit: function () {let self = this.handlers.thatself.visible2 = true},},},},//主题theme: 'snow',placeholder: '请输入正文',},}},watch: {value(newVal, oldVal) {console.log(newVal, oldVal)if (newVal) {this.articleForm.artContent = newVal} else if (!newVal) {this.articleForm.artContent = ''}},},created() {this.articleForm.artContent = this.value},mounted() {this._initEditor()//初始化编辑器this.initButton() //自定义图标(秀米,135)// 暴露方法绑定到window上,给public\xiumi-ue-dialog-v5.html使用window.setRichText_xm = this.setRichText_xmwindow.setRichText_135 = this.setRichText_135// 调用135页面的时候 带入数据 getHtml()window.getHtml = this.getHtml},methods:{// 初始化编辑器_initEditor() {// 初始化编辑器this.quill = this.$refs.myQuillEditor.quill// 双向绑定代码 v-modelthis.quill.on('text-change', () => {this.emitChange()this.selection = this.quill.getSelection()})// 插入内容this.firstSetHtml()// 粘贴板监听this.listenPaste()},//秀米编辑器setRichText_xm(e) {const index = this.selection ? this.selection.index : 0// console.log('光标位置',index)this.quill.insertEmbed(index || 0, 'AppPanelEmbed', e)this.visible = false},//135编辑器setRichText_135(e) {const index = this.selection ? this.selection.index : 0//这个主要是用来处理在135编辑器添加导出到quill再点击135编辑器返回到quill的重复内容this.quill.setContents([{ insert: '', attributes: { bold: true } },{ insert: '\n' },])this.quill.insertEmbed(index || 0, 'AppPanelEmbed', e)this.visible2 = false},emitChange() {// 获取到quill 根dom中的htmllet html = this.articleForm.artContentconst quill = this.quillconst text = this.quill.getText()if (html === '<p><br></p>') html = ''// v-model相关this.$emit('input', html)this.$emit('change', { html, text, quill })// 返回quill中文本长度// bug注意:这个方法无法计算秀米代码的中的文字长度!this.$emit('getConetntLength', this.quill.getLength())},// 回显内容时检查秀米代码firstSetHtml() {// value 为回显内容if (this.value) {// 判断是否有秀米和或135元素if (this.value.indexOf('xiumi.us') > -1 ||this.value.indexOf('135editor.com') > -1) {const originNode = new DOMParser().parseFromString(this.value,'text/html').body.childNodesthis.nodesInQuill(originNode)} else {// 正常插入this.quill.clipboard.dangerouslyPasteHTML(this.value)}}},// 根据node类型分发处理nodesInQuill(originNode) {for (let i = originNode.length - 1; i >= 0; i--) {if (originNode[i].localName === 'section') {// 秀米类型代码,走新blotthis.setRichText_xm(originNode[i].outerHTML, 0)this.setRichText_135(originNode[i].outerHTML, 0)} else {// 正常插入this.quill.clipboard.dangerouslyPasteHTML(0,originNode[i].outerHTML)}}},// 监听粘贴板(请求接口把秀米图片本地化处理)  //注意!注意!注意!如果是本地复制粘贴的话,会走此方法,如果是线上直接点击秀米编辑器上的√ 直接导入,可以考虑在chang时贴入此段代码listenPaste() {var that = thisvar imageArr = []this.quill.root.addEventListener('paste', (e) => {that.msg = (e.clipboardData || window.clipboardData).getData('text/html')// //匹配图片var imgReg = /<img.*?(?:>|\/>)/gi // eslint-disable-line// //匹配src属性var srcReg = /src=[\'\"]?([^\'\"]*)[\'\"]?/i // eslint-disable-lineif (that.msg) {if (that.msg.indexOf('xiumi.us') > -1 ||that.msg.indexOf('_135editor') > -1) {that.msg.replace(imgReg, function (txt) {return txt.replace(srcReg, function (src) {var img_src = src.match(srcReg)[1]//正则把?x-oss-process后面的都去掉img_src = img_src.replace(/\?.*/i, '')imageArr.push(img_src)})})const parmas = {urlList: imageArr,}if (imageArr.length != 0) {//    如果有图片则 请求接口上传图片uploadUrlImgs(parmas).then((res) => {if (res.data && res.data.length) {var index = 0while (index < res.data.length) {//接口返回图片根据index替换that.msg = that.msg.replace(imageArr[index],res.data[index])index++that.$emit('change', that.msg)// 富文本const value = new DOMParser().parseFromString(that.msg,'text/html').body.childNodes // 获取nodese.preventDefault() // 阻止复制动作e.stopPropagation() // 阻止冒泡that.nodesInQuill(value) // 根据不同标签,使用不同的插入方法}} else {// 富文本const value1 = new DOMParser().parseFromString(that.msg,'text/html').body.childNodes // 获取nodese.preventDefault() // 阻止复制动作e.stopPropagation() // 阻止冒泡that.nodesInQuill(value1) // 根据不同标签,使用不同的插入方法}}).catch(() => {})} else {// 富文本const value1 = new DOMParser().parseFromString(that.msg,'text/html').body.childNodes // 获取nodese.preventDefault() // 阻止复制动作e.stopPropagation() // 阻止冒泡that.nodesInQuill(value1) // 根据不同标签,使用不同的插入方法}}}})//以下是不需要请求接口,直接使用秀米的图片地址// this.quill.root.addEventListener('paste', (e) => {//   let msg = (e.clipboardData || window.clipboardData).getData(//     'text/html'//   ) // 获取粘贴板文本//   if (msg) {//     if (//       msg.indexOf('xiumi.us') > -1 ||//       msg.indexOf('_135editor') > -1//     ) {//       let value = new DOMParser().parseFromString(msg, 'text/html').body//         .childNodes // 获取nodes//       e.preventDefault() // 阻止复制动作//       e.stopPropagation() // 阻止冒泡//       this.nodesInQuill(value) // 根据不同标签,使用不同的插入方法//     }//   }// })},//  自定义图标(秀米,135)initButton() {const sourceEditorButton = document.querySelector('.ql-insertMetric')sourceEditorButton.innerHTML = `<button id="custom-button-xiumi" title="秀米" ></button>`const sourceEditorButtonotEdit = document.querySelector('.ql-otEdit')sourceEditorButtonotEdit.innerHTML = `<button id="custom-button-135" title="135编辑器" ></button>`},// 获取html内容getHtml() {return this.articleForm.artContent},}
}
</script>

5.css

<style lang="scss" scoped>::v-deep(#custom-button-xiumi) {background-size: contain;background-repeat: no-repeat;height: 16px;width: 33px;background-image: url('../../../assets/img/xiumi-connect-icon.png');}::v-deep(#custom-button-135) {background-size: contain;background-repeat: no-repeat;height: 16px;width: 33px;background-image: url('../../../assets/img/editor-135-icon.png');}</style>

本文参考:https://www.freesion.com/article/97151190977/
https://blog.csdn.net/qq_41621896/article/details/121975513

vue+elementui+quill富文本框+秀米编辑器和135编辑器相关推荐

  1. vue+elementui+quill富文本框实现(富文本框最大化和最小化)

    效果图:(点击最大化放大,富文本框撑满整个屏幕:点击还原回到原来的位置) 1 .html <quill-editorref="myQuillEditor"v-model=&q ...

  2. vue+element-ui实现富文本(含有图片粘贴拖拽上传)

    vue+element-ui实现富文本(含有图片粘贴拖拽上传) Just For Share | 仅仅分享 首先需要安装 cnpm i vue-quill-editor -D 富文本编辑器 cnpm ...

  3. vue中wangeditor富文本框的使用方法

    vue中使用的富文本插件最多的就是 wangeditor 和 vue-quill-editor .开始我用的是 vue-quill-editor,后来又换成了 wangeditor.为啥呢?因为 vu ...

  4. vue中的富文本框的使用(vue-quill-editor)

    一.安装 vue-quill-editor npm install vue-quill-editor 二.在main.js中引入 import VueQuillEditor from 'vue-qui ...

  5. vue项目 quill 富文本支持表格

    最近修改公司模版,富文本内可以插入表格,选择了几款,最终确定使用quill+quill-better-table, quill 2.0版本的表格功能比较弱,故所需要quill-better-table ...

  6. 若依框架图片上传、富文本框编辑器功能

    文章目录 一.前言 二.效果 三.编码过程 1.前端: index.vue projectShow.js 富文本框: Editor/index.vue 图片上传:ImgUploadCropper/in ...

  7. quill 富文本编辑器

    富文本quill 富文本框中上传图片的缩放功能 vue.config.js添加如下配置 import "./resizeImg.js"➡ resizeImg.js下载链接 3.以下 ...

  8. vue--echarts 图标库、excel导出、面包屑组件、富文本框、地图、前端使用代理访问、监控生产环境or开发环境

    目录 一.echarts 图标库 1.echarts的基础 2.项目中的使用 二.execl导出 三.面包屑组件 四.富文本框 五.地图 六.vite 构建配置 七.后端未开跨域资源共享,前端使用代理 ...

  9. vue富文本框(插入文本、图片、视频)的使用

    今天在vue里面插入富文本遇到了一些小坑在这里提供给大家用于参考,如有错误,望多加指正. 我这里使用的是Element-ui的上传图片组件 首先引入Element-ui(这个我就不作赘述了,详情参考e ...

  10. 使用vue制作富文本框

    这里分享一个富文本框插件,如图 使用方法: 1-安装 npm install --save vue2-editor或者yarn add vue2-editor 2- 使用 // Basic Use - ...

最新文章

  1. 【[HAOI2011]Problem c】
  2. 针对阿片类药物使用障碍的药物重定位
  3. 【Flutter】顶部导航栏实现 ( Scaffold | DefaultTabController | TabBar | Tab | TabBarView )
  4. JavaScript学习篇(3)
  5. php有哪些屏蔽错误的方法,php常见的错误类型及屏蔽方法
  6. Spring Clould负载均衡重要组件:Ribbon中重要类的用法
  7. java反序列化漏洞 tomcat_CVE-2020-9484 Apache Tomcat反序列化漏洞浅析
  8. springboot 整合mybats问题
  9. 使用pip安装virtualenv时出现问题
  10. Dotnet中Socket网络通信
  11. python编程(改进的线程同步方式)
  12. 如何在Windows上的Git Bash中退出'git diff'的结果? [重复]
  13. 关于android studio的配置记录
  14. 不同线程产生的map,会崩溃?
  15. 判断回文字符串-C语言
  16. 批处理FOR 中的Delims和Tokens总结
  17. 服装开源平台让女装血拼开始
  18. SPI通讯协议详解 基于STM32
  19. WUSTOJ 1923 一笔画 【回溯】
  20. 世界杯:用Python分析热门夺冠球队

热门文章

  1. AIDE手机编程初级教程(零基础向) 3.2.2 设计欢迎页(补充)
  2. 关于 LiDAR 点云数据处理的一些思考
  3. 图解设计模式:行为型模式之责任链模式
  4. OptiStruct] Altair OptiStruct之前世今生
  5. 刘意JavaSE 学习笔记 Day12-Day14——字符串API(String/StringBuffer/StringBuilder...)
  6. 点译PDF的翻译器或者PDF阅读器插件
  7. CRM客户管理系统能为企业带来什么好处?
  8. java 输入语句_java怎样输入语句
  9. 用友U8案例教程委外管理前台操作
  10. 【Transfer Learning】泛化到未知域:域泛化 (Domain Generalization) 综述论文