Commit 9671827f387bd08fa5e4412cc403501735c2e94c

Authored by 梁灏
1 parent 3affd6f3

update Upload

update Upload
src/components/upload/ajax.js 0 → 100755
  1 +// https://github.com/ElemeFE/element/blob/dev/packages/upload/src/ajax.js
  2 +
  3 +function getError(action, option, xhr) {
  4 + const msg = `fail to post ${action} ${xhr.status}'`;
  5 + const err = new Error(msg);
  6 + err.status = xhr.status;
  7 + err.method = 'post';
  8 + err.url = action;
  9 + return err;
  10 +}
  11 +
  12 +function getBody(xhr) {
  13 + const text = xhr.responseText || xhr.response;
  14 + if (!text) {
  15 + return text;
  16 + }
  17 +
  18 + try {
  19 + return JSON.parse(text);
  20 + } catch (e) {
  21 + return text;
  22 + }
  23 +}
  24 +
  25 +export default function upload(option) {
  26 + if (typeof XMLHttpRequest === 'undefined') {
  27 + return;
  28 + }
  29 +
  30 + const xhr = new XMLHttpRequest();
  31 + const action = option.action;
  32 +
  33 + if (xhr.upload) {
  34 + xhr.upload.onprogress = function progress(e) {
  35 + if (e.total > 0) {
  36 + e.percent = e.loaded / e.total * 100;
  37 + }
  38 + option.onProgress(e);
  39 + };
  40 + }
  41 +
  42 + const formData = new FormData();
  43 +
  44 + if (option.data) {
  45 + Object.keys(option.data).map(key => {
  46 + formData.append(key, option.data[key]);
  47 + });
  48 + }
  49 +
  50 + formData.append(option.filename, option.file);
  51 +
  52 + xhr.onerror = function error(e) {
  53 + option.onError(e);
  54 + };
  55 +
  56 + xhr.onload = function onload() {
  57 + if (xhr.status < 200 || xhr.status >= 300) {
  58 + return option.onError(getError(action, option, xhr), getBody(xhr));
  59 + }
  60 +
  61 + option.onSuccess(getBody(xhr));
  62 + };
  63 +
  64 + xhr.open('post', action, true);
  65 +
  66 + if (option.withCredentials && 'withCredentials' in xhr) {
  67 + xhr.withCredentials = true;
  68 + }
  69 +
  70 + const headers = option.headers || {};
  71 +
  72 + // if (headers['X-Requested-With'] !== null) {
  73 + // xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
  74 + // }
  75 +
  76 + for (let item in headers) {
  77 + if (headers.hasOwnProperty(item) && headers[item] !== null) {
  78 + xhr.setRequestHeader(item, headers[item]);
  79 + }
  80 + }
  81 + xhr.send(formData);
  82 +}
... ...
src/components/upload/index.js
  1 +import Upload from './upload.vue';
  2 +
  3 +export default Upload;
0 4 \ No newline at end of file
... ...
src/components/upload/upload.vue
1 1 <template>
2   -
  2 + <div
  3 + :class="classes"
  4 + @click="handleClick"
  5 + @drop.prevent="onDrop"
  6 + @dragover.prevent="dragOver = true"
  7 + @dragleave.prevent="dragOver = false">
  8 + <input
  9 + v-el:input
  10 + :class="[prefixCls + '-input']"
  11 + type="file"
  12 + @change="handleChange"
  13 + :multiple="multiple"
  14 + :accept="accept">
  15 + <slot></slot>
  16 + </div>
3 17 </template>
4 18 <script>
  19 + import ajax from './ajax';
  20 + import { oneOf } from '../../utils/assist';
  21 +
  22 + const prefixCls = 'ivu-upload';
  23 +
5 24 export default {
6   - props: {},
  25 + props: {
  26 + action: {
  27 + type: String,
  28 + required: true
  29 + },
  30 + headers: {
  31 + type: Object,
  32 + default () {
  33 + return {}
  34 + }
  35 + },
  36 + multiple: {
  37 + type: Boolean,
  38 + default: false
  39 + },
  40 + data: {
  41 + type: Object
  42 + },
  43 + name: {
  44 + type: String,
  45 + default: 'file'
  46 + },
  47 + withCredentials: {
  48 + type: Boolean,
  49 + default: false
  50 + },
  51 + showUploadList: {
  52 + type: Boolean,
  53 + default: true
  54 + },
  55 + type: {
  56 + type: String,
  57 + validator (value) {
  58 + return oneOf(value, ['select', 'drag']);
  59 + }
  60 + },
  61 + format: {
  62 + type: Array,
  63 + default () {
  64 + return [];
  65 + }
  66 + },
  67 + accept: {
  68 + type: String
  69 + },
  70 + maxSize: {
  71 + type: Number
  72 + },
  73 + beforeUpload: Function,
  74 + onProgress: {
  75 + type: Function,
  76 + default () {
  77 + return {};
  78 + }
  79 + },
  80 + onSuccess: {
  81 + type: Function,
  82 + default () {
  83 + return {};
  84 + }
  85 + },
  86 + onError: {
  87 + type: Function,
  88 + default () {
  89 + return {};
  90 + }
  91 + },
  92 + onRemove: {
  93 + type: Function,
  94 + default () {
  95 + return {};
  96 + }
  97 + },
  98 + onPreview: {
  99 + type: Function,
  100 + default () {
  101 + return {};
  102 + }
  103 + },
  104 + onExceededSize: {
  105 + type: Function,
  106 + default () {
  107 + return {};
  108 + }
  109 + },
  110 + onFormatError: {
  111 + type: Function,
  112 + default () {
  113 + return {};
  114 + }
  115 + },
  116 + defaultFileList: {
  117 + type: Array,
  118 + default() {
  119 + return [];
  120 + }
  121 + }
  122 + },
7 123 data () {
8   - return {};
  124 + return {
  125 + prefixCls: prefixCls,
  126 + dragOver: false,
  127 + fileList: [],
  128 + tempIndex: 1
  129 + };
  130 + },
  131 + computed: {
  132 + classes () {
  133 + return [
  134 + `${prefixCls}`,
  135 + {
  136 + [`${prefixCls}-drag`]: this.type === 'drag',
  137 + [`${prefixCls}-dragOver`]: this.dragOver
  138 + }
  139 + ];
  140 + },
  141 +
  142 + },
  143 + methods: {
  144 + handleClick () {
  145 + this.$els.input.click();
  146 + },
  147 + handleChange (e) {
  148 + const files = e.target.files;
  149 +
  150 + if (!files) {
  151 + return;
  152 + }
  153 + this.uploadFiles(files);
  154 + this.$els.input.value = null;
  155 + },
  156 + onDrop (e) {
  157 + this.dragOver = false;
  158 + this.uploadFiles(e.dataTransfer.files);
  159 + },
  160 + uploadFiles (files) {
  161 + let postFiles = Array.prototype.slice.call(files);
  162 + if (!this.multiple) postFiles = postFiles.slice(0, 1);
  163 +
  164 + if (postFiles.length === 0) return;
  165 +
  166 + postFiles.forEach(file => {
  167 + this.upload(file);
  168 + });
  169 + },
  170 + upload (file) {
  171 + if (!this.beforeUpload) {
  172 + return this.post(file);
  173 + }
  174 +
  175 + const before = this.beforeUpload(file);
  176 + if (before && before.then) {
  177 + before.then(processedFile => {
  178 + if (Object.prototype.toString.call(processedFile) === '[object File]') {
  179 + this.post(processedFile);
  180 + } else {
  181 + this.post(file);
  182 + }
  183 + }, () => {
  184 + // this.$emit('cancel', file);
  185 + });
  186 + } else if (before !== false) {
  187 + this.post(file);
  188 + } else {
  189 + // this.$emit('cancel', file);
  190 + }
  191 + },
  192 + post (file) {
  193 + this.handleStart(file);
  194 + let formData = new FormData();
  195 + formData.append(this.name, file);
  196 +
  197 + ajax({
  198 + headers: this.headers,
  199 + withCredentials: this.withCredentials,
  200 + file: file,
  201 + data: this.data,
  202 + filename: this.name,
  203 + action: this.action,
  204 + onProgress: e => {
  205 + this.handleProgress(e, file);
  206 + },
  207 + onSuccess: res => {
  208 + this.handleSuccess(res, file);
  209 + },
  210 + onError: (err, response) => {
  211 + this.handleError(err, response, file);
  212 + }
  213 + });
  214 + },
  215 + handleStart (file) {
  216 + file.uid = Date.now() + this.tempIndex++;
  217 + const _file = {
  218 + status: 'uploading',
  219 + name: file.name,
  220 + size: file.size,
  221 + percentage: 0,
  222 + uid: file.uid,
  223 + showProgress: true
  224 + };
  225 +
  226 + // check format
  227 + if (this.format.length) {
  228 + const _file_format = _file.name.split('.').pop().toLocaleLowerCase();
  229 + const checked = this.format.some(item => item.toLocaleLowerCase() === _file_format);
  230 + if (checked) {
  231 + this.onFormatError(file);
  232 + return;
  233 + }
  234 + }
  235 +
  236 + // check maxSize
  237 + if (this.maxSize) {
  238 + if (_file.size > this.maxSize * 1024) {
  239 + this.onExceededSize(file);
  240 + return;
  241 + }
  242 + }
  243 +
  244 + this.fileList.push(_file);
  245 + },
  246 + getFile (file) {
  247 + const fileList = this.fileList;
  248 + let target;
  249 + fileList.every(item => {
  250 + target = file.uid === item.uid ? item : null;
  251 + return !target;
  252 + });
  253 + return target;
  254 + },
  255 + handleProgress (e, file) {
  256 + const _file = this.getFile(file);
  257 + this.onProgress(e, _file, this.fileList);
  258 + _file.percentage = e.percent || 0;
  259 + },
  260 + handleSuccess (res, file) {
  261 + const _file = this.getFile(file);
  262 +
  263 + if (_file) {
  264 + _file.status = 'finished';
  265 + _file.response = res;
  266 +
  267 + this.onSuccess(res, _file, this.fileList);
  268 +
  269 + setTimeout(() => {
  270 + _file.showProgress = false;
  271 + }, 1000);
  272 + }
  273 + },
  274 + handleError (err, response, file) {
  275 + const _file = this.getFile(file);
  276 + const fileList = this.fileList;
  277 +
  278 + _file.status = 'fail';
  279 +
  280 + fileList.splice(fileList.indexOf(_file), 1);
  281 +
  282 + this.onError(err, response, file);
  283 + },
  284 + handleRemove(file) {
  285 + const fileList = this.fileList;
  286 + fileList.splice(fileList.indexOf(file), 1);
  287 + this.onRemove(file, fileList);
  288 + },
  289 + handlePreview(file) {
  290 + if (file.status === 'finished') {
  291 + this.onPreview(file);
  292 + }
  293 + },
  294 + clearFiles() {
  295 + this.fileList = [];
  296 + }
  297 + },
  298 + watch: {
  299 + defaultFileList: {
  300 + immediate: true,
  301 + handler(fileList) {
  302 + this.fileList = fileList.map(item => {
  303 + item.status = 'finished';
  304 + item.percentage = 100;
  305 + item.uid = Date.now() + this.tempIndex++;
  306 + return item;
  307 + });
  308 + }
  309 + }
9 310 },
10   - computed: {},
11   - methods: {}
12 311 };
13 312 </script>
14 313 \ No newline at end of file
... ...
test/routers/upload.vue
1 1 <template>
2   -
  2 + <Upload action="/qiniu" :max-size="10000">
  3 + <i-button>上传</i-button>
  4 + </Upload>
3 5 </template>
4 6 <script>
5 7 export default {
... ...