1 <template>
2 <div class="vue-uploader">
3 <div class="file-list">
4 <section v-for="(file, index) of files" class="file-item draggable-item">
5 <img :src="file.src" alt="" ondragstart="return false;">
6 <p class="file-name">{{file.name}}</p>
7 <span class="file-remove" @click="remove(index)">+</span>
8 </section>
9 <section v-if="status === 'ready'" class="file-item">
10 <div @click="add" class="add">
11 <span>+</span>
12 </div>
13 </section>
14 </div>
15
16 <section v-if="files.length !== 0" class="upload-func">
17 <div class="progress-bar">
18 <section v-if="uploading" :width="(percent * 100) + '%'">{{(percent * 100) + '%'}}</section>
19 </div>
20 <div class="operation-box">
21 <button v-if="status === 'ready'" @click="submit">上传</button>
22 <button v-if="status === 'finished'" @click="finished">完成</button>
23 </div>
24 </section>
25 <input type="file" accept="image/*" @change="fileChanged" ref="file" multiple="multiple">
26
27 <el-upload
28 action="https://jsonplaceholder.typicode.com/posts/"
29 list-type="picture-card"
30 :auto-upload="false"
31 :limit="9"
32 :on-preview="handlePictureCardPreview"
33 :on-remove="handleRemove"
34 :http-request="uploadFile"
35 ref="upload"
36 accept="image/png,image/gif,image/jpg,image/jpeg"
37 >
38 <i class="el-icon-plus"></i>
39 </el-upload>
40 <el-dialog :visible.sync="dialogVisible">
41 <img width="100%" :src="dialogImageUrl" alt="">
42 </el-dialog>
43 <el-button type="primary" @click="subPicForm">上传</el-button>
44 </div>
45 </template>
46
47 <script>
48 import axios from "axios"
49
50 export default {
51 // props: {
52 // src: {
53 // type: String,
54 // required: true
55 // }
56 // },
57 data() {
58 return {
59 status: 'ready',
60 files: [],
61 point: {},
62 uploading: false,
63 percent: 0,
64 dialogImageUrl: '',
65 dialogVisible: false,
66 formDate: ""
67 }
68 },
69 methods: {
70 add() {
71 this.$refs.file.click()
72 },
73 submit() {
74 if (this.files.length === 0) {
75 console.warn('no file!');
76 return
77 }
78 const formData = new FormData();
79 this.files.forEach((item) => {
80 formData.append(item.name, item.file)
81 });
82 const xhr = new XMLHttpRequest();
83 xhr.upload.addEventListener('progress', this.uploadProgress, false);
84 xhr.open('POST', "/api/upload", this.src, true);
85 this.uploading = true;
86 xhr.send(formData);
87 xhr.onload = () => {
88 this.uploading = false;
89 if (xhr.status === 200 || xhr.status === 304) {
90 this.status = 'finished';
91 console.log('upload success!')
92 } else {
93 console.log(`error:error code ${xhr.status}`)
94 }
95 }
96 },
97 finished() {
98 this.files = [];
99 this.status = 'ready'
100 },
101 remove(index) {
102 this.files.splice(index, 1)
103 },
104 fileChanged() {
105 const list = this.$refs.file.files;
106 for (let i = 0; i < list.length; i++) {
107 if (!this.isContain(list[i])) {
108 const item = {
109 name: list[i].name,
110 size: list[i].size,
111 file: list[i]
112 };
113 this.html5Reader(list[i], item);
114 this.files.push(item)
115 }
116 }
117 this.$refs.file.value = ''
118 },
119 // 将图片文件转成BASE64格式
120 html5Reader(file, item) {
121 const reader = new FileReader();
122 reader.onload = (e) => {
123 this.$set(item, 'src', e.target.result)
124 };
125 reader.readAsDataURL(file)
126 },
127 isContain(file) {
128 this.files.forEach((item) => {
129 if (item.name === file.name && item.size === file.size) {
130 return true
131 }
132 });
133 return false
134 },
135 // 上传进度
136 uploadProgress(evt) {
137 const component = this;
138 if (evt.lengthComputable) {
139 const percentComplete = Math.round((evt.loaded * 100) / evt.total);
140 component.percent = percentComplete / 100
141 } else {
142 console.warn('upload progress unable to compute')
143 }
144 },
145 // elementUI上传
146 uploadFile(file) {
147 this.formDate.append('file', file.file);
148 },
149 handlePictureCardPreview(file) {
150 this.dialogImageUrl = file.url;
151 this.dialogVisible = true;
152 },
153 handleRemove(file, fileList) {
154 console.log(file, fileList);
155 },
156 subPicForm() {
157 this.formDate = new FormData();
158 this.$refs.upload.submit();
159 this.formDate.append('WS_CODE', "12133");
160 let config = {
161 headers: {
162 'Content-Type': 'multipart/form-data'
163 }
164 };
165 axios.post("/api/upload", this.formDate, config).then(res => {
166 console.log(res)
167 }).catch(res => {
168 console.log(res)
169 })
170 }
171 }
172 }
173 </script>
174
175 <style scoped>
176 .vue-uploader {
177 border: 1px solid #e5e5e5;
178 }
179
180 .vue-uploader .file-list {
181 padding: 10px 0px;
182 }
183
184 .vue-uploader .file-list:after {
185 content: '';
186 display: block;
187 clear: both;
188 visibility: hidden;
189 line-height: 0;
190 height: 0;
191 font-size: 0;
192 }
193
194 .vue-uploader .file-list .file-item {
195 float: left;
196 position: relative;
197 width: 100px;
198 text-align: center;
199 }
200
201 .vue-uploader .file-list .file-item img {
202 width: 80px;
203 height: 80px;
204 border: 1px solid #ececec;
205 }
206
207 .vue-uploader .file-list .file-item .file-remove {
208 position: absolute;
209 right: 12px;
210 display: none;
211 top: 4px;
212 width: 14px;
213 height: 14px;
214 color: white;
215 cursor: pointer;
216 line-height: 12px;
217 border-radius: 100%;
218 transform: rotate(45deg);
219 background: rgba(0, 0, 0, 0.5);
220 }
221
222 .vue-uploader .file-list .file-item:hover .file-remove {
223 display: inline;
224 }
225
226 .vue-uploader .file-list .file-item .file-name {
227 margin: 0;
228 height: 40px;
229 word-break: break-all;
230 font-size: 14px;
231 overflow: hidden;
232 text-overflow: ellipsis;
233 display: -webkit-box;
234 -webkit-line-clamp: 2;
235 -webkit-box-orient: vertical;
236 }
237
238 .vue-uploader .add {
239 width: 80px;
240 height: 80px;
241 margin-left: 10px;
242 float: left;
243 text-align: center;
244 line-height: 80px;
245 border: 1px dashed #ececec;
246 font-size: 30px;
247 cursor: pointer;
248 }
249
250 .vue-uploader .upload-func {
251 display: flex;
252 padding: 10px;
253 margin: 0px;
254 background: #f8f8f8;
255 border-top: 1px solid #ececec;
256 }
257
258 .vue-uploader .upload-func .progress-bar {
259 flex-grow: 1;
260 }
261
262 .vue-uploader .upload-func .progress-bar section {
263 margin-top: 5px;
264 background: #00b4aa;
265 border-radius: 3px;
266 text-align: center;
267 color: #fff;
268 font-size: 12px;
269 transition: all .5s ease;
270 }
271
272 .vue-uploader .upload-func .operation-box {
273 flex-grow: 0;
274 padding-left: 10px;
275 }
276
277 .vue-uploader .upload-func .operation-box button {
278 padding: 4px 12px;
279 color: #fff;
280 background: #007ACC;
281 border: none;
282 border-radius: 2px;
283 cursor: pointer;
284 }
285
286 .vue-uploader > input[type="file"] {
287 display: none;
288 }
289 </style>