困扰笔者很多天的问题
一个vue页面,v-for 循环多个富文本编辑器组件,在上传图片时,无法唯一确定当前编辑器的实例,会造成传一张图片,所有编辑器内都显示或者只是第一个编辑器显示
解决方法
1. 方法一 支持图片上传(上传至服务器后,富文本中存入地址)
- 借助 el-upload 组件完成上传
- 自定义工具栏容器,给工具来容器增加 id 标识,用于标识哪个编辑器的工具栏发起的上传动作
- 全局配置 /src/main.js
.....
// quillEditor
// 引入quill-editor编辑器
import VueQuillEditor from 'vue-quill-editor'
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
Vue.use(VueQuillEditor)
import Quill from 'quill'
// 实现quill-editor编辑器图片上传到服务器的功能
import { ImageExtend } from 'quill-image-extend-module'
Quill.register('modules/ImageExtend', ImageExtend)
// 实现quill-editor编辑器拖拽上传图片
import { ImageDrop } from 'quill-image-drop-module'
Quill.register('modules/ImageDrop', ImageDrop)
// 实现quill-editor编辑器调整图片尺寸
import imageResize from 'quill-image-resize-module'
Quill.register('modules/imageResize', imageResize)
.....
.....
- 配置 webpack ,vue.config.js 文件
-
..... var webpack = require('webpack') .... configureWebpack: { plugins: [ new webpack.ProvidePlugin({ 'window.Quill': 'quill/dist/quill.js', 'Quill': 'quill/dist/quill.js' }) ] },
- 自定义vue-quill-editor组件,/src/views/components/qeditor2.vue
-
<template> <div> <el-row> <!-- 创建工具栏容器 --> <div :id="'aa'+callbackParam"> <!-- Add font size dropdown --> <select class="ql-size"> <option value="small"></option> <!-- Note a missing, thus falsy value, is used to reset to default --> <option selected></option> <option value="large"></option> <option value="huge"></option> </select> <!-- Add a bold button --> <button class="ql-bold"></button> <!-- Add subscript and superscript buttons --> <button class="ql-script" value="sub"></button> <button class="ql-script" value="super"></button> <button class="ql-image" title="照片"></button> <!-- 图片上传组件辅助--> <el-upload class="avatar-uploader" :action="uploadUrl" name="file" :show-file-list="false" :on-success="uploadSuccess"/> </div> <!-- 创建quill容器 --> <div id="editor" ref="editor" >{{html}}</div> </el-row> </div> </template> <script> export default { name: 'qeditor2', props: { value: String, callbackParam: { type: [String, Number], default: '' } }, data() { return { html: this.value, uploadUrl: process.env.VUE_APP_BASE_API + '/' + process.env.VUE_APP_GATEWAY_RULENGINE_URL + `/upload/file`, // 服务器上传地址 options: { theme: 'snow', modules: { ImageDrop: true, imageResize: { handleStyles: { backgroundColor: 'black', border: 'none', color: 'white' // other camelCase styles for size display }, displayStyles: { backgroundColor: 'black', border: 'none', color: 'white' }, modules: ['Resize', 'DisplaySize', 'Toolbar'] }, toolbar: { container: '#aa' + this.callbackParam, handlers: { image: this.handleImgUpload } } } } } }, mounted() { this.init() }, methods: { init() { let dom = this.$el.querySelector('#editor') this.quill = new Quill(dom, this.options) const _this = this this.quill.on('text-change', function(delta, oldDelta, source) { // 获取富文本组件实例 _this.html = _this.$refs.editor.children[0].innerHTML _this.$emit("quillContentInput", _this.html, _this.callbackParam) }) this.$emit("qeditorInstancesSet", this.callbackParam, this.quill) console.log("手动初始化quill实例,并调用父页面的回调函数,存储实例对象" + this.quill) }, handleImgUpload(value) { if (value) { // 调用element的图片上传组件 console.log("id=" + this.callbackParam + "的工具栏触发quill富文本触发图像上传") document.querySelector('#aa'+ this.callbackParam+' .avatar-uploader .el-upload .el-upload__input').click() } else { this.quill.format('image', false) } }, uploadSuccess(res) { // 获取富文本组件实例 let quill = this.$emit("getQeditorInstance", this.callbackParam ).quill console.log("根据id=" + this.callbackParam + ",从父页面获取quill实例对象,quill=" + quill) // 如果上传成功 if (res.code === 200 && res.data) { // 获取光标所在位置 let length = quill.selection.savedRange.index // 插入图片,res为服务器返回的图片链接地址 quill.insertEmbed(length, 'image', res.data) // 调整光标到最后 quill.setSelection(length + 1) } else { // 提示信息,需引入Message this.$message.error('图片插入失败!') } } } } </script>
- 父页面调用子组件,/src/views/test.vue
-
<template> <div> <div v-for="(banner,index) in bannerList" :key="index" > <keep-alive> <qeditor2 :value="choiceList[index].value" :callback-param="index" @quillContentInput="optionQuillContent" @qeditorInstancesSet="qeditorInstancesSet" @getQeditorInstance="qeditorInstancesGet"></qeditor2> </keep-alive> </div> </div> </template> <script> import qeditor2 from './components/qeditor2' export default { name: "ueditor", components: { qeditor2 }, data() { return { bannerList: [1, 2], choiceList: [ { value: '123' }, { value: '456' } ], // 存放 quill 组件实例 qeditorInstances: new Map() } }, methods: { // 子组件富文本内容改变时的回调方法 optionQuillContent(newVel, index) { this.choiceList[index] = newVel console.log('父节点收集富文本内容:' + this.choiceList) }, qeditorInstancesSet(key, quillObj) { this.qeditorInstances.set(key, quillObj) }, qeditorInstancesGet(key) { this.qeditorInstances.get(key) } } } </script>
2. 方法二 支持图片上传(上传至服务器后,富文本中存入地址)
- 使用 quill自带的 quill-image-extend-module 扩展,完成上传
- 全局配置 /src/main.js
-
..... // quillEditor // 引入quill-editor编辑器 import VueQuillEditor from 'vue-quill-editor' import 'quill/dist/quill.core.css' import 'quill/dist/quill.snow.css' import 'quill/dist/quill.bubble.css' Vue.use(VueQuillEditor) import Quill from 'quill' // 实现quill-editor编辑器图片上传到服务器的功能 import { ImageExtend } from 'quill-image-extend-module' Quill.register('modules/ImageExtend', ImageExtend) // 实现quill-editor编辑器拖拽上传图片 import { ImageDrop } from 'quill-image-drop-module' Quill.register('modules/ImageDrop', ImageDrop) // 实现quill-editor编辑器调整图片尺寸 import imageResize from 'quill-image-resize-module' Quill.register('modules/imageResize', imageResize) ..... .....
- 配置 webpack ,vue.config.js 文件
-
..... var webpack = require('webpack') .... configureWebpack: { plugins: [ new webpack.ProvidePlugin({ 'window.Quill': 'quill/dist/quill.js', 'Quill': 'quill/dist/quill.js' }) ] },
- 自定义vue-quill-editor组件,/src/views/components/qeditor3.vue
-
<template> <div> <el-row> <div class="quill-wrap"> <quill-editor v-model="html" ref="myQuillEditor" :options="options" @blur="onEditorBlur($event)" @focus="onEditorFocus($event)" @ready="onEditorReady($event)"> > </quill-editor> </div> </el-row> </div> </template> <script> import { container, QuillWatch } from 'quill-image-extend-module' export default { name: 'qeditor3', props: { value: { type: [Number, Object, Array, String], default: '' }, callbackParam: { type: [Number, Object, Array, String], default: '' }, }, data() { return { html: this.value, options: { theme: 'snow', modules: { ImageDrop: true, imageResize: { handleStyles: { backgroundColor: 'black', border: 'none', color: 'white' // other camelCase styles for size display }, displayStyles: { backgroundColor: 'black', border: 'none', color: 'white' }, modules: ['Resize', 'DisplaySize', 'Toolbar'] }, ImageExtend: { loading: true, name: 'file', action: process.env.VUE_APP_BASE_API + '/' + process.env.VUE_APP_GATEWAY_RULENGINE_URL + `/upload/file`, response: (res) => { debugger return res.data } }, toolbar: { container: container, handlers: { 'image': function() { QuillWatch.emit(this.quill.id) } } } } } } }, methods: { // 失去焦点 onEditorBlur(quill) { this.$emit("quillContentInput", this.html, this.callbackParam) console.log('editor blur!', quill) }, // 光标进入编辑器 onEditorFocus(quill) { console.log('editor focus!', quill) }, onEditorReady(quill) { console.log('editor ready!', quill) } }, computed: { editor() { return this.$refs.myQuillEditor.quill } }, mounted() { console.log('this is current quill instance object', this.editor) } } </script>
- 父页面调用子组件,/src/views/test.vue
<template>
<div>
<div v-for="(banner,index) in bannerList" :key="index" >
<keep-alive>
<qeditor3 :value="choiceList[index].value" :callback-param="index" @quillContentInput="optionQuillContent" ></qeditor3>
</keep-alive>
</div>
</div>
</template>
<script>
import qeditor3 from './components/qeditor3'
export default {
name: "ueditor",
components: {
qeditor3
},
data() {
return {
bannerList: [1, 2],
choiceList: [
{ value: '123' },
{ value: '456' }
]
}
},
methods: {
// 子组件富文本内容改变时的回调方法
optionQuillContent(newVel, index) {
this.choiceList[index] = newVel
console.log('父节点收集富文本内容:' + this.choiceList)
}
}
}
</script>
两种方法亲测都有效,官方推荐使用第二种方式