<template> <div class="wangeditor-wrap scale-style" :class="[isDisable ? 'is-disabled-editor' : '', chs ? 'ch-cn' : 'ch-en', isShowScale ? 'is-show-scale' : 'is-no-show-scale']" :style="{width: isShowScale ? 794 * curScale + 'px' : ''}" ref="rootDiv" > <Toolbar ref="toolbar" style="border-bottom: 1px solid #ccc" :editor="editor" :defaultConfig="isShowScale ? toolbarConfig : toolbarConfig2" mode="default" /> <Editor :style="{'background': isDisable ? '#f1f1f1' : '','height': heightStr,'overflow':'auto'}" style="width: 100%;" v-model="model" :defaultConfig="editorConfig" mode="default" @onCreated="onCreated" @onChange="onChange" @onBlur="onBlur" @onFocus="onFocus" @customPaste="handlePaste" /> <i class="el-icon-s-opportunity quickFix" title="快速格式化" v-if="isShowScale" @click="fixFont(editor)" /> </div> </template> <script> import { Editor, Toolbar } from "@wangeditor/editor-for-vue"; import { SlateTransforms,SlateText ,SlateElement } from '@wangeditor/editor' export default { name: "RichTextEditorNew", components: { Editor, Toolbar }, props: { value: String, disabled: Boolean, placeholder: { type: String, default: '请输入...' }, insertParams: { type: Object, default: () => { return { isShowInsertFn: false, insertContent: '' } } }, // 重置问题 isReset: { type: Boolean, default: false }, gtxgidtxtMark: { type: String, default: '' }, chs: { type: Boolean, default: true }, maxLength:{ type: Number }, heightStr:{ type:String, default:"400px" }, isShowScale: { type: Boolean, default: false } }, watch: { isDisable (newVal) { if (newVal) { this.editor.disable() } else { this.editor.enable() } }, isReset: { handler (newVal) { if (newVal) { this.model = this.gtxgidtxtMark } } }, }, computed: { model: { get() { return this.value; }, set(newVal) { this.$emit("input", newVal); } }, mode() { return this.$store.state.Status.mode; }, isDisable: { get() { return this.mode === "display" || this.disabled; }, } }, data() { return { editor: null, toolbarConfig: { toolbarKeys: [ 'bold', 'clearStyle', 'color', 'bgColor','fontSize', 'fontFamily', 'lineHeight', 'indent', 'delIndent', 'underline', 'insertTable', 'justifyLeft', 'justifyRight', 'justifyCenter', 'justifyJustify', 'divider', 'blockquote', 'headerSelect', 'redo', 'undo', 'fullScreen', { key: 'group-more-style', title: '插入业务变量', // 必填 iconSvg: '', // 可选 } ], excludeKeys: this.insertParams.isShowInsertFn ? [] : ['group-more-style'] }, toolbarConfig2: { toolbarKeys: this.isShowScale?[ 'bold', 'clearStyle', 'color', 'bgColor','fontSize', 'fontFamily', 'lineHeight', 'indent', 'delIndent', 'justifyLeft', 'justifyRight', 'justifyCenter', 'justifyJustify', 'divider', 'blockquote', 'headerSelect', 'redo', 'undo', 'fullScreen', { key: 'group-more-style', title: '插入业务变量', // 必填 iconSvg: '', // 可选 }]: ['redo', 'undo','fullScreen', { key: 'group-more-style', title: '插入业务变量', // 必填 iconSvg: '', // 可选 } ], excludeKeys: this.insertParams.isShowInsertFn ? [] : ['group-more-style'] }, editorConfig: { // placeholder: this.placeholder, MENU_CONF: { fontSize:{ fontSizeList:[ // '0.6em', // '0.7em', // '0.8em', // '0.9em', // '1.2em', // '1.4em', // '1.6em', // '1.8em', // '2.0em', // '2.2em', // '2.4em', // '2.6em', // '2.8em', // '3.0em', ] }, lineHeight:{ lineHeightList:[ '1.5' ] }, fontFamily: { fontFamilyList: [ // '黑体', // { name: '仿宋', value: '仿宋' }, '宋体', // '楷体', // '标楷体', 'Arial', // 'Tahoma', // 'Verdana', 'Times New Roman', // 'Courier New', ] } } }, curScale: 1 }; }, mounted() { this.initCustomEvent() this.$nextTick(() => { this.initWangeditorWrapWidth() window.addEventListener('resize', this.initWangeditorWrapWidth) }) this.setWangEditor() }, methods: { onCreated(editor) { this.editor = Object.seal(editor); if (this.isDisable) { this.editor.disable() } else { this.editor.enable() } }, onBlur(){ if(this.chs){ let curtext = this.editor.getHtml(); if (curtext.indexOf('O') !== -1) { curtext = curtext.replace(/O/g, '<span style="font-family: Arial;">O</span>'); this.editor.setHtml(curtext); } } this.$emit("blur"); }, onChange(){ this.$emit("change"); }, onFocus(){ this.$emit("focus"); }, initCustomEvent () { setTimeout(() => { let customDom = document.querySelector("button[data-menu-key='group-more-style']") if (customDom) { customDom.addEventListener('click', this.customDomClick) } }, 500) }, customDomClick () { if (this.disabled) { return; } console.log('插入内容成功:', this.insertParams.insertContent) this.editor.insertText(this.insertParams.insertContent) }, initWangeditorWrapWidth () { if (this.isShowScale) { let contentWidth = document.body.clientWidth - 340 if (contentWidth > 1588) { this.curScale = 2 } else { this.curScale = contentWidth / 794 } this.$el.querySelector('.w-e-text-container').style.fontSize = this.curScale * 18.6 + 'px'; } }, walkJson(editor,cur,copy,parent){ if(editor != cur){ //赋值当前元素 if(editor.isVoid(cur)){ //如果是image、video return; }else if(SlateText.isText(cur)){ copy.text=cur.text // if(cur.hasOwnProperty("bold")){ // copy.bold = cur.bold // } if(cur.hasOwnProperty("underline")){ copy.underline = cur.underline } }else if(cur.type){ if(cur.type == 'pre'){ return } //拷贝类型 copy.type = cur.type if(copy.type.startsWith("header")){ copy.type= "paragraph" } let propsArr=[ 'textAlign', 'indent', 'ordered', 'level', 'width', 'isHeader', 'colSpan', 'rowSpan', ] propsArr.forEach(prop=>{ if(cur.hasOwnProperty(prop)){ let val = cur[prop] if(prop == 'indent'){ val = '2em' } copy[prop] = val } }) }else{ return; } parent.children.push(copy) } if(cur.children){ copy.children=[] for(let node of cur.children){ //赋值项作为parent,新建子copy节点 this.walkJson(editor,node,{},copy) } } }, fixFont(editor){ let copyNodes = {children:[]} this.walkJson(editor,editor,copyNodes,null) editor.clear() editor.selectAll() SlateTransforms.removeNodes(editor) SlateTransforms.insertNodes(editor, copyNodes.children) this.onBlur() }, handlePaste(editor,event,callback){ let text = event.clipboardData.getData("text/plain") let rtf = event.clipboardData.getData("text/rtf") let html = event.clipboardData.getData("text/html") if(this.isShowScale && rtf && html){ //word粘贴的 callback(true) //延时修正 setTimeout(()=>this.fixFont(editor),100) return true } // this.$confirm("是否去除源格式?",'提示',{ // confirmButtonText: '去除', // cancelButtonText: '保留', // type:'info' // }).then(()=>{ // let text = event.clipboardData.getData("text/plain") // editor.insertText(text) // event.preventDefault() // callback(false) // }).catch(()=>{ // callback(true) // }) if(true){ let text = event.clipboardData.getData("text/plain") let textList = text.split(/\r?\n/g) textList.map((lineItem) => { editor.insertText(lineItem) editor.insertBreak(); }) // 欧和零 if(this.chs){ let curtext = editor.getHtml(); if (curtext.indexOf('O') !== -1) { curtext = curtext.replace(/O/g, '<span style="font-family: Arial;">O</span>'); editor.setHtml(curtext); } } event.preventDefault() callback(false) return false } return true }, getCharWidth(){ if(window['COU_FONT'+this.cols]){ let textAreaWidth = window['COU_FONT'+this.cols] return textAreaWidth } let div = document.createElement("span") div.innerHTML = `<div class="viewFitText viewPureText " style="padding:0 !important;font-size:18.6px !important">${'M'.repeat(65)}</div>` document.body.appendChild(div) let rect = div.children[0].getBoundingClientRect() let width = rect.width let textAreaWidth = width document.body.removeChild(div) window['COU_FONT'+this.cols] = textAreaWidth return textAreaWidth }, setWangEditor(){ if(this.isShowScale){ return; } let charWidth = this.getCharWidth() let element = this.$refs.rootDiv.getElementsByClassName("w-e-scroll") if(element && element.length){ element = element[0] element.style.padding = `10px calc((100% - ${charWidth+'px'} - 20px) / 2)` } } }, beforeUpdate(){ this.setWangEditor() }, beforeDestroy() { const editor = this.editor; if (editor == null) return; editor.destroy(); // 组件销毁时,及时销毁编辑器 // 解绑事件 let customDom = document.querySelector("button[data-menu-key='group-more-style']") if (customDom) { customDom.removeEventListener('click', this.customDomClick) } window.removeEventListener('resize', this.initWangeditorWrapWidth) } }; </script> <style scoped lang="less"> .wangeditor-wrap { border: 1px solid #ccc!important; z-index: 10000!important; // width: 1588px; /deep/ .w-e-bar-divider { background-color: #fff; } /deep/ &.w-e-full-screen-container { z-index: 10000!important; } /deep/ .w-e-scroll { // padding: 0 10px; padding: 10px calc((100% - 65em) / 2); } /deep/ .w-e-text-container { font-size: 20px; padding: 0; width: 100%; } /deep/ .w-e-text-container p { margin: 0!important; } } // 文本输入框被放大的样式 .scale-style { margin: auto; /deep/ .w-e-text-container { padding: 10px!important; font-size: 18.6px; } /deep/ .w-e-text-placeholder { font-size: 24px; top: 24px!important; left: 100px!important; } /deep/ .w-e-text-container .w-e-scroll { padding: 80px 10% 100px 8%; } } .is-show-scale { &.w-e-full-screen-container { z-index: 10000!important; /deep/ .w-e-text-container .w-e-scroll { padding: 80px calc(10% + 140px) 100px calc(8% + 140px); } } } .is-no-show-scale { &.w-e-full-screen-container { z-index: 10000!important; /deep/ .w-e-text-container .w-e-scroll { padding: 80px calc(10% + 175px) 100px calc(8% + 175px); } } } .is-disabled-editor { /deep/ .w-e-bar { background: #DFDCE6!important; } /deep/ .w-e-text-container { background: #DFDCE6!important; } } .ch-en { /deep/ .w-e-text-container { font-family: 'Times New Roman'; } } .is-no-show-scale.ch-en{ /deep/ .w-e-text-container { font-family: 'Courier New' !important; } } .ch-cn { /deep/ .w-e-text-container { font-family: '宋体'; } } .quickFix{ font-size: 1.5em; font-weight: bold; color: var(--primary-color); position: absolute; top: 5em; cursor: pointer; z-index: 9; } </style>