vue + iview 实现视频上传、vue+quill 图片上传

介绍了在普通开发中利用 vue + iviewaxios quill 富文本编辑器,开发后台视频上传、以及改造 quill 的图片上传功能

后台开发本着主要实现目的原则,采用 iview 前端框架,刚开始试用了 element 的框架,但是上传部分感觉不如 iview 好用一些。
vue 的使用上并不是特别熟练,只要项目上有机会,就强迫自己用上,折磨自己几次之后,对 vue 的常用方法算比较熟悉了

图片效果图后期补上

视频上传部分代码展示如下

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
<div class="fl" id="uploader-video">
<input type="hidden" name="video_str" v-model="videoInput">
<div class="video-upload-list" v-for="item in uploadList">
<template v-if="item.status === 'finished'">
<video :src="item.path" controls="controls" width="350" height="180"></video>
<div class="video-upload-list-cover">
<icon type="ios-eye-outline" @click.native="handleView(item.path, item.name)"></icon>
<icon type="ios-trash-outline" @click.native="handleRemove(item)"></icon>
</div>
</template>
<template v-else>
<i-progress v-if="item.showProgress" :percent="item.percentage" hide-info></i-progress>
</template>
</div>

<upload
ref="upload"
:show-upload-list="false"
:default-file-list="defaultList"
:on-success="handleSuccess"
:format="['mp4']"
:max-size="10240"
:on-format-error="handleFormatError"
:on-exceeded-size="handleMaxSize"
:before-upload="handleBeforeUpload"
multiple
type="drag"
action="index.php?app=activities&ctl=admin_common_uploader&act=uploadVideo"
style="display: inline-block;width:58px;">
<div style="width: 58px;height:58px;line-height: 58px;">
<icon type="ios-camera" size="20"></icon>
</div>
</upload>
<modal :title="videoName" v-model="visible" fullscreen>
<video :src="previewPath" v-if="visible" controls="controls" width="100%"></video>
</modal>

</div>

上面代码没有写什么注释,开发文档写的比较详细,开发文档 传送门


quill 富文本编辑器html 代码如下

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
<div id="standalone-container" style="max-width: 720px">
<!-- Create the editor container -->
<div id="toolbar-container">
<!--<span class="ql-formats">-->
<!--<select class="ql-font"></select>-->
<!--<select class="ql-size"></select>-->
<!--</span>-->
<!--<span class="ql-formats">-->
<!--<button class="ql-bold"></button>-->
<!--<button class="ql-italic"></button>-->
<!--<button class="ql-underline"></button>-->
<!--<button class="ql-strike"></button>-->
<!--</span>-->
<!--<span class="ql-formats">-->
<!--<select class="ql-color"></select>-->
<!--<select class="ql-background"></select>-->
<!--</span>-->
<!--<span class="ql-formats">-->
<!--<button class="ql-script" value="sub"></button>-->
<!--<button class="ql-script" value="super"></button>-->
<!--</span>-->
<!--<span class="ql-formats">-->
<!--<button class="ql-header" value="1"></button>-->
<!--<button class="ql-header" value="2"></button>-->
<!--<button class="ql-blockquote"></button>-->
<!--<button class="ql-code-block"></button>-->
<!--</span>-->
<!--<span class="ql-formats">-->
<!--<button class="ql-list" value="ordered"></button>-->
<!--<button class="ql-list" value="bullet"></button>-->
<!--<button class="ql-indent" value="-1"></button>-->
<!--<button class="ql-indent" value="+1"></button>-->
<!--</span>-->
<span class="ql-formats">
<button class="ql-direction" value="rtl"></button>
<select class="ql-align"></select>
</span>
<span class="ql-formats">
<!--<button class="ql-link"></button>-->
<button class="ql-image"></button>
<!--<button class="ql-video"></button>-->
<!--<button class="ql-formula"></button>-->
</span>
<!--<span class="ql-formats">-->
<!--<button class="ql-clean"></button>-->
<!--</span>-->
</div>

<div id="editor-container" style="height: 350px">
your text
</div>
</div>
<input type="hidden" name="intro" value="">

<!--富文本编辑器图片-->
<input type="hidden" name="rtxImageIdJson" v-model="rtxImageIdJson">
<input id="uploadImg" type="file" style="display:none" accept="image/png, image/jpeg, image/gif" @change="uploadImage">

quill 文档传送门在这里
可以看到我上面放开的文本编辑器功能并不多,你可以根据自己需要,去掉需要使用的功能
上传图片给后台,后台返回的id需要暂存一下,另外 quill 上传图片功能自己创造一个 file ,用于主动触发上传事件,请参见下方的 js 代码


下面是所有 js 操作。
需要注意的可能就是,当你渲染这个页面的时候,加载文件不像 this.data 这种赋值,而是通过 this.$refs.upload.fileList; 来实现的

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
let Main = {
data(){
return {
defaultList: [],
videoName: '',
previewPath:'',
visible: false,
uploadList: [],
videoIds:[],
rtxImgIds:[],
}
},
methods: {
//预览视频
handleView (path, name) {
this.videoName = name;
this.previewPath = path;
this.visible = true;
},
//删除视频
handleRemove (file) {
const fileList = this.$refs.upload.fileList;
this.$refs.upload.fileList.splice(fileList.indexOf(file), 1);
this.videoIds.splice(this.videoIds.indexOf(file.videoId), 1);
},
//视频上传成功
handleSuccess (res, file) {
if (!res.status) {
this.$Message.error(res.msg);
return false;
}
file.path = res.data.filePath;
file.name = res.data.fileName;
this.videoIds.push(res.data.videoId);
},
//错误提示
handleFormatError (file) {
this.$Notice.warning({
title: '文件格式错误',
desc: '文件名为 ' + file.name + '格式错误, 请上传mp4格式.'
});
},
//错误提示
handleMaxSize (file) {
this.$Notice.warning({
title: '上传文件错误',
desc: '文件 ' + file.name + ' 太大了,超过了10M'
});
},
//错误提示
handleBeforeUpload () {
const check = this.uploadList.length < 5;
if (!check) {
this.$Notice.warning({
title: '最多只能上传5个视频'
});
}
return check;
},

//初始化quill富文本编辑器
initQuill () {
// this.$Message.info('这是一个提示');
const quill = new Quill('#editor-container', {
modules: {
toolbar: "#toolbar-container",
imageResize: {
displaySize: true
},
},
placeholder: '请输入课程描述...',
theme: 'snow' // or 'bubble'
});
this.quill = quill;
this.quill.getModule("toolbar").addHandler("image", this.uploadImageHandler)
},
//quill富文本编辑器上传图片动作
uploadImageHandler() {
const input = document.querySelector('#uploadImg');
input.value = '';
input.click();
},
//quill富文本编辑器上传图片请求
async uploadImage (event) {
const form = new FormData();
form.append('upload_file', event.target.files[0]);
const res = await axios({
url:'?your_uploader_image_url',
method:'post',
data:form,
headers: { 'Content-Type': 'multipart/form-data' },
responseType:'json'
}).then((res)=>{ return res.data.data});

const addImageRange = this.quill.getSelection();
const newRange = 0 + (addImageRange !== null ? addImageRange.index : 0);
this.rtxImgIds.push(res.image_id);
this.quill.insertEmbed(newRange, 'image', res.url);
this.quill.setSelection(1 + newRange);
},
//编辑页面加载video
async renderVideo() {
var activityId = "<{$course.course_id ? $course.course_id : ''}>";
var vm = this;
await axios.get('index.php?app=activities&ctl=admin_course_manage&act=getVideoList&cid=' + activityId).then(function (response) {
// vm.defaultList = response.data;
vm.defaultList = response.data.video_list;
vm.videoIds = response.data.video_ids;
vm.$nextTick(() => {
vm.uploadList = vm.$refs.upload.fileList;
});
});

}
},
computed:{
//视频上传成功后,返回id,push到双向绑定的videoid input的value中
videoInput: function () {
return JSON.stringify({ids:this.videoIds});
},
rtxImageIdJson: function () {
return JSON.stringify({ids:this.rtxImgIds});
}
},
mounted () {
this.renderVideo();
// this.uploadList = this.$refs.upload.fileList;
this.initQuill()
},
beforeDestroy () {
this.quill = null;
delete this.quill;
},
};

var Component = Vue.extend(Main);
new Component().$mount('#x-g-basic');
Author: rexmolo
Link: http://rexmolo.github.io/2019/06/17/quill-vue-axios-make-form/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.