一. 为什么要做自定义上传,搞这么麻烦干什么?
我司要求所有的资源上传都不通过服务器处理,直接上传到阿里云对象存储。
二. 先说组件自带的方法
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
12handleImageSuccessQuill(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
9props: {
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>