update Upload

update Upload
This commit is contained in:
梁灏 2017-01-19 18:16:41 +08:00
parent 3affd6f365
commit 9671827f38
4 changed files with 393 additions and 7 deletions

82
src/components/upload/ajax.js Executable file
View file

@ -0,0 +1,82 @@
// https://github.com/ElemeFE/element/blob/dev/packages/upload/src/ajax.js
function getError(action, option, xhr) {
const msg = `fail to post ${action} ${xhr.status}'`;
const err = new Error(msg);
err.status = xhr.status;
err.method = 'post';
err.url = action;
return err;
}
function getBody(xhr) {
const text = xhr.responseText || xhr.response;
if (!text) {
return text;
}
try {
return JSON.parse(text);
} catch (e) {
return text;
}
}
export default function upload(option) {
if (typeof XMLHttpRequest === 'undefined') {
return;
}
const xhr = new XMLHttpRequest();
const action = option.action;
if (xhr.upload) {
xhr.upload.onprogress = function progress(e) {
if (e.total > 0) {
e.percent = e.loaded / e.total * 100;
}
option.onProgress(e);
};
}
const formData = new FormData();
if (option.data) {
Object.keys(option.data).map(key => {
formData.append(key, option.data[key]);
});
}
formData.append(option.filename, option.file);
xhr.onerror = function error(e) {
option.onError(e);
};
xhr.onload = function onload() {
if (xhr.status < 200 || xhr.status >= 300) {
return option.onError(getError(action, option, xhr), getBody(xhr));
}
option.onSuccess(getBody(xhr));
};
xhr.open('post', action, true);
if (option.withCredentials && 'withCredentials' in xhr) {
xhr.withCredentials = true;
}
const headers = option.headers || {};
// if (headers['X-Requested-With'] !== null) {
// xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
// }
for (let item in headers) {
if (headers.hasOwnProperty(item) && headers[item] !== null) {
xhr.setRequestHeader(item, headers[item]);
}
}
xhr.send(formData);
}

View file

@ -0,0 +1,3 @@
import Upload from './upload.vue';
export default Upload;

View file

@ -1,13 +1,312 @@
<template> <template>
<div
:class="classes"
@click="handleClick"
@drop.prevent="onDrop"
@dragover.prevent="dragOver = true"
@dragleave.prevent="dragOver = false">
<input
v-el:input
:class="[prefixCls + '-input']"
type="file"
@change="handleChange"
:multiple="multiple"
:accept="accept">
<slot></slot>
</div>
</template> </template>
<script> <script>
import ajax from './ajax';
import { oneOf } from '../../utils/assist';
const prefixCls = 'ivu-upload';
export default { export default {
props: {}, props: {
data () { action: {
return {}; type: String,
required: true
},
headers: {
type: Object,
default () {
return {}
}
},
multiple: {
type: Boolean,
default: false
},
data: {
type: Object
},
name: {
type: String,
default: 'file'
},
withCredentials: {
type: Boolean,
default: false
},
showUploadList: {
type: Boolean,
default: true
},
type: {
type: String,
validator (value) {
return oneOf(value, ['select', 'drag']);
}
},
format: {
type: Array,
default () {
return [];
}
},
accept: {
type: String
},
maxSize: {
type: Number
},
beforeUpload: Function,
onProgress: {
type: Function,
default () {
return {};
}
},
onSuccess: {
type: Function,
default () {
return {};
}
},
onError: {
type: Function,
default () {
return {};
}
},
onRemove: {
type: Function,
default () {
return {};
}
},
onPreview: {
type: Function,
default () {
return {};
}
},
onExceededSize: {
type: Function,
default () {
return {};
}
},
onFormatError: {
type: Function,
default () {
return {};
}
},
defaultFileList: {
type: Array,
default() {
return [];
}
}
},
data () {
return {
prefixCls: prefixCls,
dragOver: false,
fileList: [],
tempIndex: 1
};
},
computed: {
classes () {
return [
`${prefixCls}`,
{
[`${prefixCls}-drag`]: this.type === 'drag',
[`${prefixCls}-dragOver`]: this.dragOver
}
];
},
},
methods: {
handleClick () {
this.$els.input.click();
},
handleChange (e) {
const files = e.target.files;
if (!files) {
return;
}
this.uploadFiles(files);
this.$els.input.value = null;
},
onDrop (e) {
this.dragOver = false;
this.uploadFiles(e.dataTransfer.files);
},
uploadFiles (files) {
let postFiles = Array.prototype.slice.call(files);
if (!this.multiple) postFiles = postFiles.slice(0, 1);
if (postFiles.length === 0) return;
postFiles.forEach(file => {
this.upload(file);
});
},
upload (file) {
if (!this.beforeUpload) {
return this.post(file);
}
const before = this.beforeUpload(file);
if (before && before.then) {
before.then(processedFile => {
if (Object.prototype.toString.call(processedFile) === '[object File]') {
this.post(processedFile);
} else {
this.post(file);
}
}, () => {
// this.$emit('cancel', file);
});
} else if (before !== false) {
this.post(file);
} else {
// this.$emit('cancel', file);
}
},
post (file) {
this.handleStart(file);
let formData = new FormData();
formData.append(this.name, file);
ajax({
headers: this.headers,
withCredentials: this.withCredentials,
file: file,
data: this.data,
filename: this.name,
action: this.action,
onProgress: e => {
this.handleProgress(e, file);
},
onSuccess: res => {
this.handleSuccess(res, file);
},
onError: (err, response) => {
this.handleError(err, response, file);
}
});
},
handleStart (file) {
file.uid = Date.now() + this.tempIndex++;
const _file = {
status: 'uploading',
name: file.name,
size: file.size,
percentage: 0,
uid: file.uid,
showProgress: true
};
// check format
if (this.format.length) {
const _file_format = _file.name.split('.').pop().toLocaleLowerCase();
const checked = this.format.some(item => item.toLocaleLowerCase() === _file_format);
if (checked) {
this.onFormatError(file);
return;
}
}
// check maxSize
if (this.maxSize) {
if (_file.size > this.maxSize * 1024) {
this.onExceededSize(file);
return;
}
}
this.fileList.push(_file);
},
getFile (file) {
const fileList = this.fileList;
let target;
fileList.every(item => {
target = file.uid === item.uid ? item : null;
return !target;
});
return target;
},
handleProgress (e, file) {
const _file = this.getFile(file);
this.onProgress(e, _file, this.fileList);
_file.percentage = e.percent || 0;
},
handleSuccess (res, file) {
const _file = this.getFile(file);
if (_file) {
_file.status = 'finished';
_file.response = res;
this.onSuccess(res, _file, this.fileList);
setTimeout(() => {
_file.showProgress = false;
}, 1000);
}
},
handleError (err, response, file) {
const _file = this.getFile(file);
const fileList = this.fileList;
_file.status = 'fail';
fileList.splice(fileList.indexOf(_file), 1);
this.onError(err, response, file);
},
handleRemove(file) {
const fileList = this.fileList;
fileList.splice(fileList.indexOf(file), 1);
this.onRemove(file, fileList);
},
handlePreview(file) {
if (file.status === 'finished') {
this.onPreview(file);
}
},
clearFiles() {
this.fileList = [];
}
},
watch: {
defaultFileList: {
immediate: true,
handler(fileList) {
this.fileList = fileList.map(item => {
item.status = 'finished';
item.percentage = 100;
item.uid = Date.now() + this.tempIndex++;
return item;
});
}
}
}, },
computed: {},
methods: {}
}; };
</script> </script>

View file

@ -1,5 +1,7 @@
<template> <template>
<Upload action="/qiniu" :max-size="10000">
<i-button>上传</i-button>
</Upload>
</template> </template>
<script> <script>
export default { export default {