一. 为什么要做自定义上传,搞这么麻烦干什么?
我司要求所有的资源上传都不通过服务器处理,直接上传到阿里云对象存储。
二. 先说组件自带的方法
1. quill本身支持
2. 拦截自定义处理
- 源码1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34editorOption: { 
 modules: {
 ImageExtend: { // 如果不作设置,即{} 则依然开启复制粘贴功能且以base64插入
 name: 'fileFile', // 图片参数名
 action:'www.img:8080', // 服务器地址, 如果action为空,则采用base64插入图片
 size: 5, // 可选参数 图片大小,单位为M,1M = 1024kb
 // response 为一个函数用来获取服务器返回的具体图片地址
 // 例如服务器返回{code: 200; data:{ url: 'baidu.com'}} 则 return res.data.url
 response: (res) => {// 图片上传成功或错误 回调方法 成功后将图片地址return出去
 // 这里将后台返回的地址return出去
 return res.filePath;
 },
 // 可选参数 设置请求头部xhr.setRequestHeader('Content-Type','multipart/form-data')
 headers: (xhr) => { },
 sizeError: () => {}, // 图片超过大小的回调
 start: () => {}, // 可选参数 自定义开始上传触发事件
 end: () => {}, // 可选参数 自定义上传结束触发的事件,无论成功或者失败
 error: () => {}, // 可选参数 上传失败触发的事件
 success: () => {}, // 可选参数 上传成功触发的事件
 change: (xhr, formData) => {
 // xhr.setRequestHeader('myHeader','myValue')
 // formData.append('token', 'myToken')
 } // 可选参数 每次选择图片触发,也可用来设置头部,但比headers多了一个参数,可设置formData
 },
 toolbar: {
 container: container,
 handlers: {
 'image': function (value) {
 QuillWatch.emit(this.quill.id)
 }
 }
 },
 }
 }
你会发现整个ImageExtend 属性都是图片上传相关了以及各种事件的回调方法  ,大家根据注释配置相关的信息就好了
toolbar 这个属性此处不必配置
到这里我们的使用后台的接口上传就完事了。
五. 使用Element-UI + Ali-oss直接上传到阿里云的对象存储
1. 首先安装Ali-oss
| 1 | npm install ali-oss --save | 
2. 创建oss上传的配置文件
| 1 | 
 | 
3.注意文件中的这里需要你自己oss对象存储配置
| 1 | /** | 
4. 引入Element-UI
| 1 | npm install element-ui --save | 
在main.js中注入
1
2
3
4
// 引入element-ui 全局引入
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
5. 在quill组件中添加上传组件并 稍微修改了下
| 1 | <div class="upload" style='display:none'> | 
6. 再次修改editorOption(富文本配置参数) 这次我们只需要修改toolbar属性 ,别忘了
| 1 | toolbar: { // 如果不上传图片到服务器,此处不必配置 | 
7. 封装完成,但是有个小bug

六. 多个富文本,添加图片报错
一开始我也不知道会有这样的问题,直到我司另一前端对付产品的需求一个页面需要二个富文本时。
- 分析错误原因 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12- handleImageSuccessQuill(response, file, fileList) { 
 if (response) {
 this.imageUrl = ossURL + response.name;
 // 向富文本插入图片链接
 let quill = this.$refs.myQuillEditor.quill;
 let length = quill.getSelection().index;
 // 插入图片 res.info为服务器返回的图片地址
 // 获取光标 设置属性 图片链接
 quill.insertEmbed(length, `image`, `${ossURL + response.name}`);
 quill.setSelection(length + 1); // 调整光标到最后
 }
 },- 可以可看到报错信息 index of ‘null’
- index 是我们通过quill.getSelection()获取到的 那也就是 quill.getSelection()里面没有index属性
- 我们将this.$refs.myQuillEditor.quill 打印出来看下 
 在选择第一 个上传组件并上传 没有任何问题
 当选择第二个 上传组件并上传 找不到是null??? 这是什么鬼???
- 解析:获取到的富文本实例 quill 获取不到光标的位置。
 
- 如何解决 且要保证已经完成代码不会出现问题 也不用去修改原来的代码,降低返工率 - 我们添加一个新的自定义属性props 用于获取$refs - 1 
 2
 3
 4
 5
 6
 7
 8
 9- props: { 
 value:{
 type:String,
 },
 quillEditorName:{
 type:String,
 default:'myQuillEditor',// 没有传值 默认就是myQuillEditor 有就是传过来的值
 }
 },
- 我们将页面部分修改下 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54- <template> 
 <div class="quill-wrap">
 <quill-editor v-model="content" :ref="quillEditorName" :options="editorOption" ></quill-editor>
 <el-upload
 class="avatar-uploader"
 action
 ref="upload"
 name="img"
 :show-file-list="false"
 :auto-upload="true"
 :on-error="handleImageErrorQuill"
 :on-exceed="beyondFileQuill"
 :on-success="handleImageSuccessQuill"
 :http-request="fnUploadRequestQuill"
 :before-upload="beforeAvatarUploadQuill"
 :limit="limit"
 multiple
 >
 <i class="el-icon-plus avatar-uploader-icon" :id="quillEditorName+'Img'"></i>
 </el-upload>
 </div>
 </template>
 toolbar: {
 // 如果不上传图片到服务器,此处不必配置
 container: container, // container为工具栏,此次引入了全部工具栏,也可自行配置
 handlers: {
 image: (value)=> {
 // 劫持原来的图片点击按钮事件 自定义图片上传
 if (value) {
 // 触发input框选择图片文件
 document.querySelector('#' + this.quillEditorName + 'Img').click();
 } else {
 this.quill.format("image", false);
 }
 }
 }
 }
 handleImageSuccessQuill(response, file, fileList) {
 // 上传成功
 if (response) {
 this.imageUrl = ossURL + response.name;
 // 向富文本插入图片链接
 let quill = this.$refs[this.quillEditorName].quill;
 let length = quill.getSelection().index;
 // 插入图片 res.info为服务器返回的图片地址
 // 获取光标 设置属性 图片链接
 quill.insertEmbed(length, `image`, `${ossURL + response.name}`);
 quill.setSelection(length + 1); // 调整光标到最后
 }
 },
- 修改好了 我们在试下  
- 最后贴上全部的源码1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175<template> 
 <div>
 <quill-editor
 v-model="context"
 :ref="quillEditorName"
 :options="editorOption"
 @input="$emit('update:value', $event)"
 >
 </quill-editor>
 <div class="upload" style='display:none'>
 <el-upload
 class="avatar-uploader"
 action
 ref="upload"
 name="img"
 :show-file-list="false"
 :auto-upload="true"
 :on-error="handleImageErrorQuill"
 :on-exceed="beyondFileQuill"
 :on-success="handleImageSuccessQuill"
 :http-request="fnUploadRequestQuill"
 :before-upload="beforeAvatarUploadQuill"
 :limit="limit"
 multiple
 >
 <i class="el-icon-plus avatar-uploader-icon" :id="quillEditorName+'Img'"></i>
 </el-upload>
 </div>
 </div>
 </template>
 <script>
 const ossURL = 'http://你自己的.com/'
 import {quillEditor, Quill} from 'vue-quill-editor';
 import {container, ImageExtend, QuillWatch,} from 'quill-image-extend-module';
 import {quillRedefine} from 'vue-quill-editor-upload';
 import ImageResize from 'quill-image-resize-module';
 Quill.register('modules/ImageResize', ImageResize )
 Quill.register('modules/ImageExtend', ImageExtend);
 import oss from "@/config/oss";
 export default {
 mounted () {
 this.context = this.value;
 },
 props:{
 value:{
 type:String,
 },
 quillEditorName:{
 type:String,
 default:'myQuillEditor',// 没有传值 默认就是myQuillEditor 有就是传过来的值
 }
 },
 data() {
 return {
 limit:3,
 context:'',
 // 富文本框参数设置
 editorOption: {
 modules: {
 ImageExtend: { // 如果不作设置,即{} 则依然开启复制粘贴功能且以base64插入
 name: '', // 图片参数名
 size: 5, // 可选参数 图片大小,单位为M,1M = 1024kb
 action:"", // 服务器地址, 如果action为空,则采用base64插入图片
 // response 为一个函数用来获取服务器返回的具体图片地址
 // 例如服务器返回{code: 200; data:{ url: 'baidu.com'}} 则 return res.data.url
 response: (res) => {// 图片上传成功或错误 回调方法 成功后将图片地址return出去
 return res.filePath;
 },
 headers: (xhr) => { // 可选参数 设置请求头部
 // xhr.setRequestHeader('Content-Type','multipart/form-data')
 },
 sizeError: () => {}, // 图片超过大小的回调
 start: () => {}, // 可选参数 自定义开始上传触发事件
 end: () => {}, // 可选参数 自定义上传结束触发的事件,无论成功或者失败
 error: () => {}, // 可选参数 上传失败触发的事件
 success: () => {
 }, // 可选参数 上传成功触发的事件
 change: (xhr, formData) => {
 // xhr.setRequestHeader('myHeader','myValue')
 // formData.append('token', 'myToken')
 } // 可选参数 每次选择图片触发,也可用来设置头部,但比headers多了一个参数,可设置formData
 },
 toolbar: { // 如果不上传图片到服务器,此处不必配置
 container: container, // container为工具栏,此次引入了全部工具栏,也可自行配置
 handlers: {
 'image': function (value) { // 劫持原来的图片点击按钮事件 自定义图片上传
 // 触发input框选择图片文件
 if (value) {
 document.querySelector('#' + this.quillEditorName + 'Img').click();
 } else {
 this.quill.format('image', false);
 }
 }.bind(this)
 // 或者你可以使用箭头函数
 //'image': (value) => { // 劫持原来的图片点击按钮事件 自定义图片上传
 // // 触发input框选择图片文件
 // if (value) {
 // document.querySelector('#' + this.quillEditorName + 'Img').click();
 // } else {
 /// this.quill.format('image', false);
 // }
 //}
 }
 },
 ImageResize: { //调整上传过后图片大小配置。
 displayStyles: {
 backgroundColor: 'black',
 border: 'none',
 color: 'white'
 },
 modules: [ 'Resize', 'DisplaySize','Toolbar' ]
 },
 },
 }
 }
 },
 methods: {
 // * 上传失败的回调
 handleImageErrorQuill() {
 this.$message({ message: "上传失败", type: "error" });
 },
 // * 文件超出个数限制时的钩子
 beyondFileQuill(files, fileList) {
 this.$message({ message: "只能上传" + this.limit, type: "error" });
 },
 // * 上传成功
 handleImageSuccessQuill(response, file, fileList) {
 if (response) {
 this.imageUrl = ossURL + response.name;
 // 向富文本插入图片链接
 let quill = this.$refs[this.quillEditorName].quill;
 let length = quill.getSelection().index;
 // 插入图片 res.info为服务器返回的图片地址
 // 获取光标 设置属性 图片链接
 quill.insertEmbed(length, `image`, `${ossURL + response.name}`);
 quill.setSelection(length + 1); // 调整光标到最后
 }
 },
 // * 自定义上传覆盖默认上传
 async fnUploadRequestQuill(option) {
 oss.ossUploadFile(option,'image/');
 },
 // * 上传前对图片进行验证
 beforeAvatarUploadQuill(file) {
 const isJPG = file.type === "image/jpeg" || file.type === "image/png" || file.type === "image/gif";
 const isLtM = file.size / 1024 / 1024 < 20;
 if (!isJPG) {
 this.$message.error("上传头像图片只能是 JPG,PNG,GIF 格式!");
 }
 if (!isLtM) {
 this.$message.error("上传头像图片大小不能超过 20MB!");
 }
 return isJPG && isLtM;
 }
 },
 watch: {
 // 页面
 value(newVAlue){
 this.context = newVAlue;
 },
 context(newValue){
 console.log(newValue);
 }
 },
 filters: {},
 computed: {},
 components: {
 quillEditor,
 quillRedefine,
 Quill
 }
 }
 </script>