自定义element UI的upload组件

简介

ElementUI中的upload组件使用固然很简便,但是我们可能有更复杂的应用。

比如要开发一个手写数字识别的前端,上传到的服务器的是一张手写数字的图片,返回识别的结果,这个应用无法直接由upload组件实现。

当然,我们也可以先上传,维护一个图片的token,然后后台根据这个token去取相应的数据。但这样不仅要维护一个token,还要和文件系统(磁盘)交互,要考虑上传到哪里、如何删除等问题。不如直接传递方便。

实现

自定义上传函数

绑定http-request到自定义函数即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<el-upload
class="upload-demo"
:http-request="uploadSectionFile"
ref="upload"
action=""
:on-preview="handlePreview"
:on-remove="handleRemove"
:before-remove="beforeRemove"
:limit="1"
:on-exceed="handleExceed"
:auto-upload="false"
:file-list="fileList">
<el-button type="primary" icon="el-icon-upload">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传wav文件,且不超过500kb</div>
</el-upload>

该函数只有一个参数param, 并且param.file就是我们要上传的文件对象。

1
2
3
4
5
6
function uploadSectionFile(param){
var fileObj = param.file
var form = new FormData()
form.append("file", fileObj)
// other code ....
}

实现上传进度条

上传用axios实现,进度条由axios和uploadSectionFile的param参数配合实现。

param.file.percentparam.onProjress用来显示进度条。

1
2
3
4
5
6
7
8
9
10
let config = {
onUploadProgress: progressEvent => {
var complete = (progressEvent.loaded / progressEvent.total * 100 | 0)
param.file.percent = complete
param.onProgress(param.file)
},
headers: {
'Content-Type': 'multipart/form-data'
}
}

实现上传成功状态

依旧是param参数。

1
param.onSuccess('文件上传成功')

完整代码

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
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
<template>
<div class="home">
<h1>Hello</h1>
<el-row>
<el-col :span="8">
<el-upload
class="upload-demo"
:http-request="uploadSectionFile"
ref="upload"
action=""
:on-preview="handlePreview"
:on-remove="handleRemove"
:before-remove="beforeRemove"
:limit="1"
:on-exceed="handleExceed"
:auto-upload="false"
:file-list="fileList">
<el-button type="primary" icon="el-icon-upload">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传wav文件,且不超过500kb</div>
</el-upload>
</el-col>
<el-col :span="8">
<el-button type="primary" @click="handleButton('upload-model')" icon="el-icon-upload">加载模型</el-button>
</el-col>
<el-col :span="8">
<el-button type="primary" @click="handleButton('begin-analyse')" icon="el-icon-video-play">开始分析</el-button>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<div class="row-softmax">
<h2>模型原始输出</h2>
<el-table
:data="softmax_output"
:max-height = "330"
border
style="width: 100%">
<el-table-column
prop="label"
label="标签"
width="148">
</el-table-column>
<el-table-column
prop="probability"
label="概率"
width="148">
</el-table-column>
</el-table>
</div>
</el-col>
<el-col :span="12">
<el-row>
<el-col :span="24">
<div class="time-frequency">
<img class="base64Img" :src="time_frequency_pic_base64">
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<div class="final-result">
<h2>归类</h2>
<p> final_result }} </p>
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<div class="save-result">
<el-button type="primary"><i class="el-icon-upload el-icon--right"></i>保存结果</el-button>
</div>
</el-col>
</el-row>
</el-col>
</el-row>
</div>
</template>
<script>
import { predict } from '@/api/tensorflow'
export default {
name: 'HelloWorld',
data () {
return {
fileList: [],
fileObj: '',
time_frequency_pic_base64:'',
readable_labels: [],
final_result: '',
softmax_output: [
{
'label' : '类别1',
'probability' : 0.1
},
{
'label' : '类别1',
'probability' : 0.1
},
{
'label' : '类别1',
'probability' : 0.1
},
{
'label' : '类别1',
'probability' : 0.1
},
{
'label' : '类别1',
'probability' : 0.1
}
]
}
},
methods: {
handleRemove(file, fileList) {
console.log(file, fileList);
},
handlePreview(file) {
console.log(file);
},
handleExceed(files, fileList) {
this.$message.warning(`当前限制选择 1 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`);
},
beforeRemove(file, fileList) {
return this.$confirm(`确定移除 ${ file.name }?`);
},
uploadSectionFile(param){
console.log(param)
let config = {
onUploadProgress: progressEvent => {
var complete = (progressEvent.loaded / progressEvent.total * 100 | 0)
param.file.percent = complete
param.onProgress(param.file)
},
headers: {
'Content-Type': 'multipart/form-data'
}
}
var fileObj = param.file
var form = new FormData()
form.append("file", fileObj)
predict(form, config)
.then( (data) => {
console.log(data)
this.time_frequency_pic_base64 = 'data:image/jpg;base64,' + data.data.time_frequency_pic_base64
this.final_result = data.data.final_result
this.softmax_output = data.data.softmax_output
param.onSuccess('文件上传成功')
})
},
handleButton(type){
if(type == 'upload-model'){
console.log('Not implement yet. Upload model')
}
else if(type == 'begin-analyse'){
console.log('Begin anaylyse')
this.$refs.upload.submit()
}
},
handleChange(type){
if(type == 'file'){
this.fileObj = document.getElementById("upfile").files[0]
}else if(type == 'model'){
}
}
}
}
</script>

axios

1
2
3
4
import axios from 'axios'
export function predict(data, config) {
return axios.post('your_address',data,config)
}

0%