Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 3a2ae7d

Browse files
vue-uploader
1 parent 751b6bf commit 3a2ae7d

File tree

8 files changed

+378
-0
lines changed

8 files changed

+378
-0
lines changed

‎vue-simple-uploader/app.vue‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<template>
2+
<div id="app">
3+
<div id="nav">
4+
<router-link to="/">Home</router-link>
5+
<router-link to="/about">About</router-link>
6+
</div>
7+
<router-view/>
8+
9+
<!-- 将上传组件全局注册 -->
10+
<global-uploader></global-uploader>
11+
</div>
12+
</template>
13+
14+
<script>
15+
import globalUploader from '@/components/GlobalUploader.vue'
16+
17+
export default {
18+
name: 'app',
19+
data() {
20+
return {}
21+
},
22+
components: {
23+
globalUploader
24+
},
25+
computed: {},
26+
created() {
27+
},
28+
watch: {},
29+
}
30+
</script>
31+
32+
<style lang="scss">
33+
</style>

‎vue-simple-uploader/demo.vue‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<!-- 一个上传事例文件 -->
2+
<template>
3+
<div>
4+
<el-button @click="upload">上传</el-button>
5+
</div>
6+
</template>
7+
8+
<script>
9+
import Bus from '@/assets/js/bus';
10+
11+
export default {
12+
data() {
13+
return {}
14+
},
15+
mounted() {
16+
// 文化上传成功的回调
17+
Bus.$on('fileSuccess', data => {
18+
console.log(data)
19+
});
20+
},
21+
computed: {},
22+
methods: {
23+
upload() {
24+
// 打开文件选择框
25+
Bus.$emit('openUploader', {
26+
id: '1111' // 传入的参数
27+
})
28+
}
29+
},
30+
watch: {},
31+
components: {}
32+
}
33+
</script>
34+
35+
<style scoped lang="scss">
36+
37+
</style>
Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
<template>
2+
<div id="global-uploader">
3+
4+
<!-- 上传 -->
5+
<uploader
6+
ref="uploader"
7+
:options="options"
8+
:autoStart="false"
9+
@file-added="onFileAdded"
10+
@file-success="onFileSuccess"
11+
@file-progress="onFileProgress"
12+
@file-error="onFileError"
13+
class="uploader-app">
14+
<uploader-unsupport></uploader-unsupport>
15+
16+
<uploader-btn id="global-uploader-btn" :attrs="attrs" ref="uploadBtn">选择文件</uploader-btn>
17+
18+
<uploader-list v-show="panelShow">
19+
<div class="file-panel" slot-scope="props" :class="{'collapse': collapse}">
20+
<div class="file-title">
21+
<h2>文件列表</h2>
22+
<div class="operate">
23+
<el-button @click="fileListShow" type="text" :title="collapse ? '展开':'折叠' ">
24+
<i class="iconfont" :class="collapse ? 'inuc-fullscreen': 'inuc-minus-round'"></i>
25+
</el-button>
26+
<el-button @click="close" type="text" title="关闭">
27+
<i class="iconfont icon-close"></i>
28+
</el-button>
29+
</div>
30+
</div>
31+
32+
<ul class="file-list">
33+
<li v-for="file in props.fileList" :key="file.id">
34+
<uploader-file :class="'file_' + file.id" ref="files" :file="file" :list="true"></uploader-file>
35+
</li>
36+
<div class="no-file" v-if="!props.fileList.length"><i class="iconfont icon-empty-file"></i> 暂无待上传文件</div>
37+
</ul>
38+
</div>
39+
</uploader-list>
40+
41+
</uploader>
42+
43+
</div>
44+
</template>
45+
46+
<script>
47+
import {ACCEPT_CONFIG} from './js/config';
48+
import Bus from './js/bus';
49+
import SparkMD5 from 'spark-md5';
50+
51+
// 这两个是我自己项目中用的,请忽略
52+
import {Ticket} from '@/assets/js/utils';
53+
import api from '@/api';
54+
55+
export default {
56+
data() {
57+
return {
58+
options: {
59+
target: api.simpleUploadURL,
60+
chunkSize: '2048000',
61+
fileParameterName: 'upfile',
62+
testChunks: true, //是否开启秒传
63+
maxChunkRetries: 3,
64+
checkChunkUploadedByResponse: function (chunk, message) {
65+
let objMessage = JSON.parse(message);
66+
if (objMessage.skipUpload) {
67+
return true;
68+
}
69+
70+
return (objMessage.uploaded || []).indexOf(chunk.offset + 1) >= 0
71+
},
72+
headers: {
73+
Authorization: Ticket.get() && "Bearer " + Ticket.get().access_token
74+
},
75+
query() {
76+
}
77+
},
78+
attrs: {
79+
accept: ACCEPT_CONFIG.getAll()
80+
},
81+
panelShow: false, //选择文件后,展示上传panel
82+
collapse: false,
83+
}
84+
},
85+
created() {
86+
},
87+
mounted() {
88+
Bus.$on('openUploader', query => {
89+
this.params = query || {};
90+
91+
if (this.$refs.uploadBtn) {
92+
$('#global-uploader-btn').click();
93+
}
94+
});
95+
},
96+
computed: {
97+
//Uploader实例
98+
uploader() {
99+
return this.$refs.uploader.uploader;
100+
}
101+
},
102+
methods: {
103+
onFileAdded(file) {
104+
this.panelShow = true;
105+
this.computeMD5(file);
106+
},
107+
onFileProgress(rootFile, file, chunk) {
108+
console.log(`上传中 ${file.name},chunk:${chunk.startByte / 1024 / 1024} ~ ${chunk.endByte / 1024 / 1024}`)
109+
},
110+
onFileSuccess(rootFile, file, response, chunk) {
111+
let res = JSON.parse(response);
112+
113+
// 服务器自定义的错误,这种错误是Uploader无法拦截的
114+
if (!res.result) {
115+
this.$message({ message: res.message, type: 'error' });
116+
return
117+
}
118+
119+
// 如果服务端返回需要合并
120+
if (res.needMerge) {
121+
api.mergeSimpleUpload({
122+
tempName: res.tempName,
123+
fileName: file.name,
124+
...this.params,
125+
}).then(res => {
126+
// 文件合并成功
127+
Bus.$emit('fileSuccess');
128+
}).catch(e => {});
129+
130+
// 不需要合并
131+
} else {
132+
Bus.$emit('fileSuccess');
133+
console.log('上传成功');
134+
}
135+
},
136+
onFileError(rootFile, file, response, chunk) {
137+
this.$message({
138+
message: response,
139+
type: 'error'
140+
})
141+
},
142+
143+
/**
144+
* 计算md5,实现断点续传及秒传
145+
* @param file
146+
*/
147+
computeMD5(file) {
148+
let fileReader = new FileReader();
149+
let time = new Date().getTime();
150+
let md5 = '';
151+
152+
file.pause();
153+
154+
fileReader.readAsArrayBuffer(file.file);
155+
156+
fileReader.onload = (e => {
157+
if (file.size != e.target.result.byteLength) {
158+
this.error('Browser reported success but could not read the file until the end.');
159+
return
160+
}
161+
162+
md5 = SparkMD5.ArrayBuffer.hash(e.target.result);
163+
164+
// 添加额外的参数
165+
this.uploader.opts.query = {
166+
...this.params
167+
}
168+
169+
console.log(`MD5计算完毕:${file.id} ${file.name} MD5:${md5} 用时:${new Date().getTime() - time} ms`);
170+
171+
file.uniqueIdentifier = md5;
172+
file.resume();
173+
});
174+
175+
fileReader.onerror = function () {
176+
this.error('FileReader onerror was triggered, maybe the browser aborted due to high memory usage.');
177+
};
178+
},
179+
180+
fileListShow() {
181+
let $list = $('#global-uploader .file-list');
182+
183+
if ($list.is(':visible')) {
184+
$list.slideUp();
185+
this.collapse = true;
186+
} else {
187+
$list.slideDown();
188+
this.collapse = false;
189+
}
190+
},
191+
close() {
192+
this.uploader.cancel();
193+
194+
this.panelShow = false;
195+
},
196+
197+
error(msg) {
198+
this.$notify({
199+
title: this.$t('c.false'),
200+
message: msg,
201+
type: 'error',
202+
duration: 2000
203+
})
204+
}
205+
},
206+
watch: {},
207+
destroyed() {
208+
Bus.$off('openUploader');
209+
},
210+
components: {}
211+
}
212+
</script>
213+
214+
<style scoped lang="scss">
215+
#global-uploader {
216+
position: fixed;
217+
z-index: 20;
218+
right: 15px;
219+
bottom: 15px;
220+
221+
.uploader-app {
222+
width: 520px;
223+
}
224+
225+
.file-panel {
226+
background-color: #fff;
227+
border: 1px solid #e2e2e2;
228+
border-radius: 7px 7px 0 0;
229+
box-shadow: 0 0 10px rgba(0, 0, 0, .2);
230+
231+
.file-title {
232+
display: flex;
233+
height: 40px;
234+
line-height: 40px;
235+
padding: 0 15px;
236+
border-bottom: 1px solid #ddd;
237+
238+
.operate {
239+
flex: 1;
240+
text-align: right;
241+
}
242+
}
243+
244+
.file-list {
245+
position: relative;
246+
height: 240px;
247+
overflow-x: hidden;
248+
overflow-y: auto;
249+
background-color: #fff;
250+
251+
> li {
252+
background-color: #fff;
253+
}
254+
}
255+
256+
&.collapse {
257+
.file-title {
258+
background-color: #E7ECF2;
259+
}
260+
}
261+
}
262+
263+
.no-file {
264+
position: absolute;
265+
top: 50%;
266+
left: 50%;
267+
transform: translate(-50%, -50%);
268+
font-size: 16px;
269+
}
270+
271+
/deep/.uploader-file-icon {
272+
&:before {
273+
content: '' !important;
274+
}
275+
276+
&[icon=image] {
277+
background: url(./images/image-icon.png);
278+
}
279+
&[icon=video] {
280+
background: url(./images/video-icon.png);
281+
}
282+
&[icon=document] {
283+
background: url(./images/text-icon.png);
284+
}
285+
}
286+
287+
/deep/.uploader-file-actions > span {
288+
margin-right: 6px;
289+
}
290+
}
291+
292+
/* 隐藏上传按钮 */
293+
#global-uploader-btn {
294+
position: absolute;
295+
clip: rect(0, 0, 0, 0);
296+
}
297+
</style>
14.4 KB
Loading[フレーム]
14.3 KB
Loading[フレーム]
14.4 KB
Loading[フレーム]

‎vue-simple-uploader/js/bus.js‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import Vue from 'vue';
2+
3+
export default new Vue();

‎vue-simple-uploader/js/config.js‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export const ACCEPT_CONFIG = {
2+
image: ['.png', '.jpg', '.jpeg', '.gif', '.bmp'],
3+
video: ['.mp4', '.rmvb', '.mkv', '.wmv', '.flv'],
4+
document: ['.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.pdf', '.txt', '.tif', '.tiff'],
5+
getAll(){
6+
return [...this.image, ...this.video, ...this.document]
7+
},
8+
};

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /