From 0567ec32f842d9bb8761ea09fc55db9c55f42f9d Mon Sep 17 00:00:00 2001 From: xuhuajiao <13476289682@163.com> Date: Thu, 11 Sep 2025 16:50:20 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=8C=E6=96=87=E6=9C=AC=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E5=99=A8=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + src/components/quillEditor/index.vue | 206 +++++++++---- src/components/quillEditor/index2.vue | 374 +++++++++++++++++++++++ src/components/quillEditor/indexlast.vue | 296 ++++++++++++++++++ src/views/inquiryMachine/content.vue | 10 +- 5 files changed, 835 insertions(+), 52 deletions(-) create mode 100644 src/components/quillEditor/index2.vue create mode 100644 src/components/quillEditor/indexlast.vue diff --git a/package.json b/package.json index c1dd4ea..804db2f 100644 --- a/package.json +++ b/package.json @@ -78,6 +78,7 @@ "qrcodejs2": "^0.0.2", "qs": "^6.10.1", "quill": "^2.0.0-dev.3", + "quill-better-table": "^1.2.10", "quill-image-resize-module": "^3.0.0", "screenfull": "4.2.0", "sm-crypto": "^0.3.2", diff --git a/src/components/quillEditor/index.vue b/src/components/quillEditor/index.vue index bc336bc..44d3603 100644 --- a/src/components/quillEditor/index.vue +++ b/src/components/quillEditor/index.vue @@ -12,6 +12,10 @@ import Quill from 'quill' import 'quill/dist/quill.snow.css' import '@/assets/styles/quillEditor.css' +import QuillBetterTable from 'quill-better-table' +import 'quill-better-table/dist/quill-better-table.css' +Quill.register({ 'modules/better-table': QuillBetterTable }, true) + var fonts = [ 'SimSun', 'SimHei', 'Microsoft-YaHei', 'KaiTi', 'FangSong', 'Arial', 'sans-serif' ] @@ -56,6 +60,31 @@ const titleConfig = { 'ql-table-delete-column': '删除列' } +// better-table配置 +const betterTable = { + // 右键菜单 + operationMenu: { + items: { + insertColumnRight: { text: '右边插入一列' }, + insertColumnLeft: { text: '左边插入一列' }, + insertRowUp: { text: '上边插入一行' }, + insertRowDown: { text: '下边插入一行' }, + mergeCells: { text: '合并单元格' }, + unmergeCells: { text: '拆分单元格' }, + deleteColumn: { text: '删除列' }, + deleteRow: { text: '删除行' }, + deleteTable: { text: '删除表格' } + }, + background: { + color: '#333' + }, + color: { + colors: ['green', 'red', 'yellow', 'blue', 'white', '#558ff2', '#595959', '#9fd9c5'], + text: '背景色:' + } + } +} + export default { name: 'Editor', props: { @@ -84,13 +113,14 @@ export default { [{ align: [] }], ['link', 'image'], ['clean'], - [ - { table: 'TD' }, - { 'table-insert-row': 'TIR' }, - { 'table-insert-column': 'TIC' }, - { 'table-delete-row': 'TDR' }, - { 'table-delete-column': 'TDC' } - ] + ['table'] + // [ + // { table: 'TD' }, + // { 'table-insert-row': 'TIR' }, + // { 'table-insert-column': 'TIC' }, + // { 'table-delete-row': 'TDR' }, + // { 'table-delete-column': 'TDC' } + // ] ], handlers: { image: function(value) { @@ -135,24 +165,37 @@ export default { this.quill.format('image', false) } }, - table: function(val) { - this.quill.getModule('table').insertTable(2, 3) - }, - 'table-insert-row': function() { - this.quill.getModule('table').insertRowBelow() - }, - 'table-insert-column': function() { - this.quill.getModule('table').insertColumnRight() - }, - 'table-delete-row': function() { - this.quill.getModule('table').deleteRow() - }, - 'table-delete-column': function() { - this.quill.getModule('table').deleteColumn() + table: function() { + // this.quill.getModule('better-table').insertTable(3, 4) + // 确保模块已加载 + if (this.quill.getModule('better-table')) { + this.quill.getModule('better-table').insertTable(3, 4) + } else { + console.error('better-table模块未正确加载') + } } + // table: function(val) { + // this.quill.getModule('table').insertTable(2, 3) + // }, + // 'table-insert-row': function() { + // this.quill.getModule('table').insertRowBelow() + // }, + // 'table-insert-column': function() { + // this.quill.getModule('table').insertColumnRight() + // }, + // 'table-delete-row': function() { + // this.quill.getModule('table').deleteRow() + // }, + // 'table-delete-column': function() { + // this.quill.getModule('table').deleteColumn() + // } } }, - table: true + table: false, + 'better-table': betterTable, + keyboard: { + bindings: QuillBetterTable.keyboardBindings + } }, placeholder: '' }, @@ -161,48 +204,61 @@ export default { }, watch: { value(newVal) { - if (newVal === this.quill.root.innerHTML) return - this.quill.setContents([]) - this.quill.clipboard.dangerouslyPasteHTML(0, newVal) + // if (newVal === this.quill.root.innerHTML) return + // this.quill.setContents([]) + // this.quill.clipboard.dangerouslyPasteHTML(0, newVal) + if (newVal === this.quill?.root.innerHTML) return + // 优化:先清除内容再粘贴新内容 + if (this.quill) { + this.quill.deleteText(0, this.quill.getLength()) + this.quill.clipboard.dangerouslyPasteHTML(0, newVal || '') + } } }, + // 关键:组件销毁时清理Quill实例和残留DOM + beforeDestroy() { + this.destroyEditor() + }, mounted() { - const dom = this.$refs.editorContainer - this.quill = new Quill(dom, this.options) + this.initEditor() + // const dom = this.$refs.editorContainer + // this.quill = new Quill(dom, this.options) - if (this.value) { - this.quill.clipboard.dangerouslyPasteHTML(this.value) - } + // if (this.value) { + // this.quill.clipboard.dangerouslyPasteHTML(this.value) + // } - // 监听内容变化并发射事件 + // // 监听内容变化并发射事件 // this.quill.on('text-change', () => { // const content = this.quill.root.innerHTML - // console.log('content', content) + // // console.log('content', content) // // this.$emit('input', content) - // // this.$emit('contentData', content) + // this.$emit('contentData', content) // }) - // 设置表格相关图标 - this.$el.querySelector('.ql-table-insert-row').innerHTML = - `` + // this.addQuillTitle() + }, + methods: { + // 初始化编辑器 + initEditor() { + const dom = this.$refs.editorContainer + if (!dom) return - this.$el.querySelector('.ql-table-insert-column').innerHTML = - `` + this.$nextTick(() => { + this.quill = new Quill(dom, this.options) - this.$el.querySelector('.ql-table-delete-row').innerHTML = - `` + if (this.value) { + this.quill.clipboard.dangerouslyPasteHTML(this.value) + } - this.$el.querySelector('.ql-table-delete-column').innerHTML = - `` + this.quill.on('text-change', () => { + const content = this.quill.root.innerHTML + this.$emit('contentData', content) + }) - this.addQuillTitle() - }, - // activated() { - // if (this.value && this.quill) { - // this.quill.clipboard.dangerouslyPasteHTML(this.value) - // } - // }, - methods: { + this.addQuillTitle() + }) + }, addQuillTitle() { const oToolBar = document.querySelector('.ql-toolbar') const aButton = oToolBar.querySelectorAll('button') @@ -222,6 +278,35 @@ export default { item.parentNode.title = titleConfig[item.classList[0]] }) }, + // 销毁编辑器实例 + destroyEditor() { + if (this.quill) { + // 1. 移除事件监听 + this.quill.off('text-change') + + // 2. 清除编辑器内容 + this.quill.deleteText(0, this.quill.getLength()) + + // 3. 销毁表格模块相关的DOM和事件 + const tableModule = this.quill.getModule('better-table') + if (tableModule && tableModule.destroy) { + tableModule.destroy() + } + + // 4. 移除编辑器容器内容 + const container = this.$refs.editorContainer + if (container) { + container.innerHTML = '' + } + + // 5. 释放实例引用 + this.quill = null + } + + // 6. 清除可能残留的表格操作菜单 + const residualMenus = document.querySelectorAll('.qlbt-operation-menu, .quill-better-table') + residualMenus.forEach(menu => menu.remove()) + }, getHtmlContent() { return this.quill.root.innerHTML }, @@ -232,5 +317,24 @@ export default { } - diff --git a/src/components/quillEditor/index2.vue b/src/components/quillEditor/index2.vue new file mode 100644 index 0000000..987876a --- /dev/null +++ b/src/components/quillEditor/index2.vue @@ -0,0 +1,374 @@ + + + + + diff --git a/src/components/quillEditor/indexlast.vue b/src/components/quillEditor/indexlast.vue new file mode 100644 index 0000000..e77e775 --- /dev/null +++ b/src/components/quillEditor/indexlast.vue @@ -0,0 +1,296 @@ + + + + + diff --git a/src/views/inquiryMachine/content.vue b/src/views/inquiryMachine/content.vue index 44f75a5..a515e2b 100644 --- a/src/views/inquiryMachine/content.vue +++ b/src/views/inquiryMachine/content.vue @@ -80,6 +80,9 @@