Browse Source

update upload

baiyaaaaa 9 years ago
parent
commit
0aaf2df436

+ 79 - 43
examples/docs/upload.md

@@ -7,33 +7,6 @@
   .demo-box {
     margin-bottom: 24px;
   }
-  .el-draggeer__uploaded-image__btns {
-    margin-top: 45px;
-    color: #fff;
-    font-size: 14px;
-
-    & .btn {
-      display: inline-block;
-
-      & span {
-        opacity: 0;
-        transition: opacity .15s linear;
-      }
-
-      &:not(:first-child) {
-        margin-left: 35px;
-      }
-
-      &:hover span {
-        opacity: 1;
-      }
-    }
-    & i {
-      display: block;
-      font-size: 26px;
-      margin-bottom: 5px;
-    }
-  }
 </style>
 <script>
   export default {
@@ -43,6 +16,16 @@
       },
       handleRemove(file, fileList) {
         console.log(file, fileList);
+      },
+      beforeUpload(file) {
+        if (file.size > 40000000) {
+          console.warn(file.name + ' is too large!');
+          return false;
+        }
+        return true;
+      },
+      handlePreview(file) {
+        console.log(file);
       }
     }
   }
@@ -51,31 +34,66 @@
 ## 基础使用
 
 <div class="demo-box">
-  <el-upload action="http://127.0.0.1:9000/upload" @filechange="handleChange" @fileremove="handleRemove">
+  <el-upload action="http://element.alpha.elenet.me/upload" :on-preview="handlePreview" :on-remove="handleRemove">
     <el-button size="small" type="primary">点击上传</el-button>
     <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
   </el-upload>
 </div>
 
 ```html
-<el-upload action="http://127.0.0.1:9000/upload" @filechange="handleChange" @fileremove="handleRemove">
+<el-upload action="http://element.alpha.elenet.me/upload" :on-preview="handlePreview" :on-remove="handleRemove">
   <el-button size="small" type="primary">点击上传</el-button>
   <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
 </el-upload>
+
+<script>
+  export default {
+    methods: {
+      handleRemove(file, fileList) {
+        console.log(file, fileList);
+      },
+      handlePreview(file) {
+        console.log(file);
+      }
+    }
+  }
+</script>
 ```
 
 ## 拖拽文件上传
 
 <div class="demo-box">
-  <el-upload action="http://127.0.0.1:9000/upload" type="drag" :multiple="true">
+  <el-upload
+    action="http://element.alpha.elenet.me/upload"
+    type="drag"
+    :multiple="true"
+    :on-preview="handlePreview"
+    :on-remove="handleRemove">
     <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
   </el-upload>
 </div>
 
 ```html
-<el-upload action="http://127.0.0.1:9000/upload" type="drag" :multiple="true">
+<el-upload
+  action="http://element.alpha.elenet.me/upload"
+  type="drag"
+  :multiple="true"
+  :on-preview="handlePreview"
+  :on-remove="handleRemove">
   <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
 </el-upload>
+<script>
+  export default {
+    methods: {
+      handleRemove(file, fileList) {
+        console.log(file, fileList);
+      },
+      handlePreview(file) {
+        console.log(file);
+      }
+    }
+  }
+</script>
 ```
 
 ## 图片缩略图模式
@@ -83,23 +101,39 @@
 上传文件类型限制为只能上传图片,并可展示本地缩略图,该模式暂不支持多选
 
 <div class="demo-box">
-  <el-upload action="http://127.0.0.1:9000/upload" type="drag" mode="image">
-    <div class="el-draggeer__uploaded-image__btns" slot="interact">
-      <span class="btn"><i class="el-icon-share"></i><span>分享图片</span></span>
-      <span class="btn"><i class="el-icon-delete"></i><span>删除</span></span>
-    </div>
+  <el-upload
+    action="http://element.alpha.elenet.me/upload"
+    type="drag"
+    :thumbnail-mode="true"
+    :on-preview="handlePreview"
+    :on-remove="handleRemove"
+  >
     <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
   </el-upload>
 </div>
 
 ```html
-<el-upload action="http://127.0.0.1:9000/upload" type="drag" mode="image">
-  <div class="el-draggeer__uploaded-image__btns" slot="interact">
-    <span class="btn"><i class="el-icon-share"></i><span>分享图片</span></span>
-    <span class="btn"><i class="el-icon-delete"></i><span>删除</span></span>
-  </div>
+<el-upload
+  action="http://element.alpha.elenet.me/upload"
+  type="drag"
+  :thumbnail-mode="true"
+  :on-preview="handlePreview"
+  :on-remove="handleRemove"
+>
   <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
 </el-upload>
+<script>
+  export default {
+    methods: {
+      handleRemove(file, fileList) {
+        console.log(file, fileList);
+      },
+      handlePreview(file) {
+        console.log(file);
+      }
+    }
+  }
+</script>
 ```
 
 ## API
@@ -113,6 +147,8 @@
 | showUploadList | 是否显示已上传文件列表 | boolean | | true |
 | type | 上传控件类型 | string | select,drag | select |
 | accept | 可选参数, 接受上传的[文件类型](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-accept), 拖拽文件上传时不受此参数影响 | string |  |  |
-| filechange | 可选参数, 上传文件改变时的回调 | function(file, fileList, event) |  |  |
-| fileremove | 可选参数, 文件列表移除文件时的回调 | function(file, fileList) |  |  |
+| onPreview | 可选参数, 点击已上传的文件链接时的钩子 | function(file) |  |  |
+| onRemove | 可选参数, 文件列表移除文件时的钩子 | function(file, fileList) |  |  |
+| beforeUpload | 可选参数, 上传文件之前的钩子,参数为上传的文件,若返回 false 或者 Promise 则停止上传。 | function(file) |  |  |
+| thumbnailMode | 是否设置为图片模式,该模式下会显示图片缩略图 | boolean | | false |
 | type | 上传控件类型 | string | select,drag | select |

+ 20 - 30
packages/theme-default/src/common/transition.css

@@ -1,25 +1,24 @@
 @charset "UTF-8";
 @import './var.css';
 
-.fade-in-transition {
-  opacity: 1;
-  transition: var(--fade-transition);
-}
-
-.fade-in-linear-enter-active {
-  opacity: 1;
+.fade-in-linear-enter-active,
+.fade-in-linear-leave-active {
   transition: var(--fade-linear-transition);
 }
 
+.fade-in-linear-enter,
+.fade-in-linear-leave,
 .fade-in-linear-leave-active {
   opacity: 0;
-  transition: var(--fade-linear-transition);
+}
+
+.fade-in-enter-active,
+.fade-in-leave-active {
+  transition: all .3s cubic-bezier(.55,0,.1,1);
 }
 
 .fade-in-enter,
-.fade-in-leave,
-.fade-in-linear-enter,
-.fade-in-linear-leave {
+.fade-in-leave-active {
   opacity: 0;
 }
 
@@ -96,28 +95,19 @@
   transition: opacity .3s cubic-bezier(.645,.045,.355,1);
 }
 .fade-enter,
-.fade-leave,
 .fade-leave-active {
   opacity: 0;
 }
 
-.slide-in-bottom-enter {
-  animation: slideInBottomEnter .3s;
-}
-.slide-in-bottom-leave {
-  animation: slideInBottomLeave .3s;
-}
-
-@keyframes slideInBottomEnter {
-  0% {
-    opacity: 0;
-    transform: translate3d(0,50%,0);
-  }
+.list-move, .list-enter-active, .list-leave-active {
+  transition: all .5s cubic-bezier(.55,0,.1,1);
 }
-
-@keyframes slideInBottomLeave {
-  to {
-    opacity: 0;
-    transform: translate3d(0,50%,0);
-  }
+.list-enter, .list-leave-active {
+  opacity: 0;
+  transform: translate(0, -30px);
 }
+/*.list-leave-active {
+  position: absolute;
+  opacity: 0;
+  transform: scaleY(0.01) translate(30px, 0);
+}*/

+ 5 - 0
packages/theme-default/src/common/var.css

@@ -23,6 +23,11 @@
   --color-black: #000;
   --color-grey: #C0CCDA;
 
+  /* Link
+  -------------------------- */
+  --link-color: #475669;
+  --link-hover-color: var(--color-primary);
+
   /* Border
   -------------------------- */
   --border-width-base: 1px;

+ 60 - 9
packages/theme-default/src/upload.css

@@ -19,6 +19,7 @@
       margin-bottom: 10px;
     }
     @e file {
+      transition: all .5s cubic-bezier(.55,0,.1,1);
       font-size: 14px;
       color: #475669;
       line-height: 32px;
@@ -33,21 +34,16 @@
       text-overflow: ellipsis;
       position: relative;
 
+      a {
+        color: #475669;
+        transition: color .3s;
+      }
       [class^="el-icon"] {
         color: #99a9bf;
         margin-right: 7px;
         height: 100%;
         line-height: inherit;
       }
-
-      &:hover {
-        background-color: #eff2f7;
-
-        .el-upload__btn-delete {
-          display: block;
-          cursor: pointer;
-        }
-      }
       & .el-progress {
         position: absolute;
         bottom: 0;
@@ -61,6 +57,21 @@
         top: 0;
         height: 100%;
       }
+      &:hover {
+        background-color: #eff2f7;
+      }
+      @when finished {
+        & a:hover {
+          color: var(--link-hover-color);
+          cursor: pointer;
+        }
+        &:hover {
+          .el-upload__btn-delete {
+            display: block;
+            cursor: pointer;
+          }   
+        }
+      }
     }
     @e tip {
       font-size: 12px;
@@ -125,6 +136,7 @@
       height: 100%;
       overflow: hidden;
       z-index: 10;
+      cursor: default;
 
       & img {
         display: block;
@@ -140,6 +152,45 @@
         height: 100%;
         background-color: rgba(#000, .72);
         text-align: center;
+
+        & .btn {
+          display: inline-block;
+          color: #fff;
+          font-size: 14px;
+          cursor: pointer;
+          vertical-align: middle;
+          transition: var(--md-fade-transition);
+          margin-top: 60px;
+
+          & i {
+            margin-top: 0;
+          }
+
+          & span {
+            opacity: 0;
+            transition: opacity .15s linear;
+          }
+
+          &:not(:first-child) {
+            margin-left: 35px;
+          }
+
+          &:hover {
+            transform: translateY(-13px);
+
+            & span {
+              opacity: 1;
+            }
+          }
+
+          & i {
+            color: #fff;
+            display: block;
+            font-size: 24px;
+            line-height: inherit;
+            margin: 0 auto 5px;
+          }
+        }
       }
 
       @e title {

+ 1 - 1
packages/upload/index.js

@@ -1,4 +1,4 @@
-const Upload = require('./src/upload');
+const Upload = require('./src/index');
 
 Upload.install = function(Vue) {
   Vue.component(Upload.name, Upload);

+ 204 - 0
packages/upload/src/index.vue

@@ -0,0 +1,204 @@
+<script>
+import UploadList from './upload-list';
+import Upload from './upload';
+import ElProgress from 'packages/progress/index.js';
+
+function noop() {
+}
+
+export default {
+  name: 'el-upload',
+
+  // extends: typeof FormData !== 'undefined' ? ajaxUpload : iframeUpload,
+  // extends: iframeUpload,
+
+  components: {
+    ElProgress,
+    UploadList,
+    Upload
+  },
+
+  props: {
+    action: {
+      type: String,
+      required: true
+    },
+    headers: {
+      type: Object,
+      default() {
+        return {
+          // 'Access-Control-Request-Methods': 'GET, PUT, POST, DELETE, OPTIONS',
+          // 'Access-Control-Request-Headers': 'Content-Type, Content-Range, Content-Disposition, Content-Description'
+        };
+      }
+    },
+    multiple: {
+      type: Boolean,
+      default: false
+    },
+    name: {
+      type: String,
+      default: 'file'
+    },
+    withCredentials: {
+      type: Boolean,
+      default: false
+    },
+    thumbnailMode: Boolean,
+    showUploadList: {
+      type: Boolean,
+      default: true
+    },
+    accept: String,
+    type: {
+      type: String,
+      default: 'select'
+    },
+    beforeUpload: Function,
+    onRemove: {
+      type: Function,
+      default: noop
+    },
+    onChange: {
+      type: Function,
+      default: noop
+    },
+    onPreview: {
+      type: Function,
+      default: noop
+    }
+  },
+
+  data() {
+    return {
+      uploadedFiles: [],
+      dragOver: false,
+      draging: false,
+      tempIndex: 1
+    };
+  },
+
+  methods: {
+    onStart(file) {
+      file.uid = Date.now() + this.tempIndex++;
+      let _file = {
+        status: 'uploading',
+        name: file.name,
+        size: file.size,
+        percentage: 0,
+        uid: file.uid,
+        showProgress: true
+      };
+
+      if (this.thumbnailMode) {
+        try {
+          _file.url = URL.createObjectURL(file);
+        } catch (err) {
+          console.log(err);
+          return;
+        }
+      }
+
+      this.uploadedFiles.push(_file);
+    },
+    onProgress(ev, file) {
+      var _file = this.getFile(file);
+      _file.percentage = ev.percent;
+    },
+    onSuccess(res, file) {
+      var _file = this.getFile(file);
+
+      _file.status = 'finished';
+      _file.response = res;
+
+      setTimeout(() => {
+        _file.showProgress = false;
+      }, 1000);
+    },
+    onError(err, file) {
+      var _file = this.getFile(file);
+      var fileList = this.uploadedFiles;
+
+      _file.status = 'fail';
+
+      fileList.splice(fileList.indexOf(_file), 1);
+      this.$emit('error', _file, fileList, err);
+    },
+    handleRemove(file) {
+      var fileList = this.uploadedFiles;
+      fileList.splice(fileList.indexOf(file), 1);
+      this.onRemove(file, fileList);
+    },
+    getFile(file) {
+      var fileList = this.uploadedFiles;
+      var target;
+      fileList.every(item => {
+        target = file.uid === item.uid ? item : null;
+        return !target;
+      });
+      return target;
+    },
+    handlePreview(file) {
+      if (file.status === 'finished') {
+        this.onPreview(file);
+      }
+    }
+  },
+
+  render(h) {
+    var uploadList;
+    if (this.showUploadList && !this.thumbnailMode) {
+      uploadList = (
+        <UploadList
+          files={this.uploadedFiles}
+          on-remove={this.handleRemove}
+          on-preview={this.handlePreview}>
+        </UploadList>
+      );
+    }
+
+    var props = {
+      props: {
+        action: this.action,
+        multiple: this.multiple,
+        'before-upload': this.beforeUpload,
+        'with-credentials': this.withCredentials,
+        name: this.name,
+        accept: this.thumbnailMode ? 'image/*' : this.accept,
+        'on-start': this.onStart,
+        'on-progress': this.onProgress,
+        'on-success': this.onSuccess,
+        'on-error': this.onError,
+        'on-preview': this.handlePreview,
+        'on-remove': this.handleRemove
+      }
+    };
+
+    if (this.type === 'select') {
+      return (
+        <div class="el-upload">
+          {uploadList}
+          <upload {...props}>
+            {this.$slots.default}
+          </upload>
+          {this.$slots.tip}
+        </div>
+      );
+    }
+
+    if (this.type === 'drag') {
+      props.props.type = 'drag';
+
+      return (
+        <div class="el-upload">
+          <upload {...props}>
+            {this.$slots.default}
+          </upload>
+          {this.$slots.tip}
+          {uploadList}
+        </div>
+      );
+    }
+  }
+};
+</script>

+ 37 - 0
packages/upload/src/upload-list.vue

@@ -0,0 +1,37 @@
+<template>
+  <transition-group tag="ul" class="el-upload__files" name="list">
+    <li
+      v-for="file in files"
+      class="el-upload__file"
+      :class="{
+        'is-finished': file.status === 'finished'
+      }"
+      :key="file"
+      @click="$emit('clickFile', file)"
+    >
+      <a class="el-upload__file__name" @click="$emit('preview', file)">
+        <i class="el-icon-document"></i>{{file.name}}
+      </a>
+      <i class="el-icon-check" v-if="file.status === 'finished' && file.showProgress"></i>
+      <span class="el-upload__btn-delete" @click="$emit('remove', file)" v-show="file.status === 'finished'">删除</span>
+      <el-progress
+        v-if="file.showProgress"
+        size="small"
+        :percentage="file.percentage"
+        :type="file.status === 'finished' ? 'green' : 'blue'">
+      </el-progress>
+    </li>
+  </transition-group>
+</template>
+<script>
+  export default {
+    props: {
+      files: {
+        type: Array,
+        default() {
+          return [];
+        }
+      }
+    }
+  };
+</script>

+ 125 - 192
packages/upload/src/upload.vue

@@ -1,187 +1,103 @@
 <template>
-  <div class="el-upload">
-    <!-- 选择类型 -->
-    <template v-if="type === 'select'">
-      <ul class="el-upload__files" v-show="showUploadList && uploadedFiles.length > 0" transition="slide-in-bottom">
-        <li class="el-upload__file" v-for="file in uploadedFiles" transition="slide-in-bottom">
-          <i class="el-icon-document"></i>{{file.name}}
-          <i class="el-icon-check" v-show="file.status === 'success'"></i>
-          <span class="el-upload__btn-delete" @click="removeFile(file)" v-show="file.status === 'finished'">删除</span>
-          <el-progress
-            v-if="file.status === 'success' || file.status === 'uploading'"
-            size="small"
-            :percentage="file.percentage"
-            :type="file.status === 'success' ? 'green' : 'blue'">
-          </el-progress>
-        </li>
-      </ul>
-      <component :is="uploadComponent"
-        :action="action",
-        :multiple="multiple",
-        :with-credentials="withCredentials",
-        :name="name",
-        :accept="accept",
-        :on-start="onStart",
-        :on-progress="onProgress",
-        :on-success="onSuccess",
-        :on-error="onError"
-      >
-        <slot></slot>
-      </component>
-      <slot name="tip"></slot>
+  <div class="el-upload__inner"
+    :class="{
+      'el-dragger': type === 'drag',
+      'is-dragOver': dragOver,
+      'is-hover': mouseover,
+      'is-showImage': showThumbnail
+    }"
+    @click="$refs.input.click()"
+    @drop.prevent="onDrop"
+    @dragover.prevent="dragOver = true"
+    @dragleave.prevent="dragOver = false"
+    @mouseenter="mouseover = true"
+    @mouseleave="mouseover = false"
+  >
+    <slot></slot>
+    <template v-if="type === 'drag' && !showThumbnail">
+      <i class="el-icon-upload"></i>
+      <div class="el-dragger__text">将文件拖到此处,或<em>点击上传</em></div>
     </template>
-
-    <!-- 拖拽类型 -->
-    <template v-if="type === 'drag'">
-      <div class="el-dragger"
-        :class="{
-          'is-dragOver': dragOver,
-          'is-draging': draging,
-          'is-hover': mouseover,
-          'is-showImage': showImageBlock
-        }"
-        @drop.prevent="dragOver = false"
-        @dragOver.prevent="dragOver = true"
-        @dragLeave.prevent="dragOver = false"
-        @mouseenter="mouseover = true"
-        @mouseleave="mouseover = false"
-      >
+    <template v-if="thumbnailMode">
+      <transition name="fade-in">
         <el-progress
           class="el-dragger__progress"
-          v-if="mode === 'image' && (image.status === 'success' || image.status === 'uploading')"
+          v-if="lastestFile.showProgress"
           size="large"
-          :percentage="image.percentage"
-          :type="image.status === 'success' ? 'green' : 'blue'">
+          :percentage="lastestFile.percentage"
+          :type="lastestFile.status === 'finished' ? 'green' : 'blue'">
         </el-progress>
-        <div class="el-dragger__uploaded-image"
-          v-if="mode === 'image' && image.status === 'finished'"
-          transition="slide-in-bottom"
-        >
-          <img :src="image.url">
-          <div v-show="mouseover" class="el-dragger__uploaded-image__interact" transition="fade-in">
-            <slot name="interact"></slot>
+      </transition>
+      <div class="el-dragger__uploaded-image" v-if="lastestFile.status === 'finished'" @click.stop>
+        <img :src="lastestFile.url">
+        <transition name="fade-in">
+          <div v-show="mouseover" class="el-dragger__uploaded-image__interact">
+            <div class="el-draggeer__uploaded-image__btns">
+              <span class="btn" @click="$refs.input.click()"><i class="el-icon-upload"></i><span>继续上传</span></span>
+              <span class="btn" @click="onPreview(lastestFile)"><i class="el-icon-search"></i><span>查看图片</span></span>
+              <span class="btn" @click="onRemove(lastestFile)"><i class="el-icon-delete"></i><span>删除</span></span>
+            </div>
           </div>
-          <h4 v-show="mouseover" class="el-dragger__uploaded-image__title" transition="slide-in-bottom">{{image.name}}</h4>
-        </div>
-        <component :is="uploadComponent"
-          :action="action",
-          :multiple="multiple",
-          :with-credentials="withCredentials",
-          :name="name",
-          :accept="accept",
-          :on-start="onStart",
-          :on-progress="onProgress",
-          :on-success="onSuccess",
-          :on-error="onError"
-        >
-          <slot></slot>
-        </component>
+        </transition>
+        <transition name="md-fade-top">
+          <h4 v-show="mouseover" class="el-dragger__uploaded-image__title">{{lastestFile.name}}</h4>
+        </transition>
       </div>
-
-      <slot name="tip" class="el-dragger__tip"></slot>
-
-      <ul class="el-upload__files"
-        v-if="mode !== 'image' && showUploadList"
-        v-show="uploadedFiles.length > 0"
-        transition="slide-in-bottom"
-      >
-        <li class="el-upload__file" v-for="file in uploadedFiles" transition="slide-in-bottom">
-          <i class="el-icon-document"></i>{{file.name}}
-          <i class="el-icon-check" v-show="file.status === 'success'"></i>
-          <span class="el-upload__btn-delete" @click="removeFile(file)" v-show="file.status === 'finished'">删除</span>
-          <el-progress
-            v-if="file.status === 'success' || file.status === 'uploading'"
-            size="small"
-            :percentage="file.percentage"
-            :type="file.status === 'success' ? 'green' : 'blue'">
-          </el-progress>
-        </li>
-      </ul>
     </template>
+    <input class="el-upload__input" type="file" ref="input" @change="handleChange" :multiple="multiple" :accept="accept">
   </div>
 </template>
 
 <script>
-import AjaxUpload from './ajax-upload';
-import IframeUpload from './iframe-upload';
-import ElProgress from 'packages/progress/index.js';
+import ajax from './ajax';
 
 export default {
-  name: 'el-upload',
-
-  // extends: typeof FormData !== 'undefined' ? ajaxUpload : iframeUpload,
-  // extends: iframeUpload,
-
-  components: {
-    ElProgress,
-    AjaxUpload,
-    IframeUpload
-  },
-
   props: {
+    type: String,
     action: {
       type: String,
       required: true
     },
-    headers: {
-      type: Object,
-      default() {
-        return {
-          // 'Access-Control-Request-Methods': 'GET, PUT, POST, DELETE, OPTIONS',
-          // 'Access-Control-Request-Headers': 'Content-Type, Content-Range, Content-Disposition, Content-Description'
-        };
-      }
-    },
-    multiple: false,
     name: {
       type: String,
       default: 'file'
     },
-    withCredentials: {
-      type: Boolean,
-      default: false
-    },
-    showUploadList: {
-      type: Boolean,
-      default: true
-    },
+    withCredentials: Boolean,
+    multiple: Boolean,
     accept: String,
-    type: {
-      type: String,
-      default: 'select'
+    onStart: Function,
+    onProgress: Function,
+    onSuccess: Function,
+    onError: Function,
+    beforeUpload: Function,
+    onPreview: {
+      type: Function,
+      default: function() {}
     },
-    mode: String
+    onRemove: {
+      type: Function,
+      default: function() {}
+    }
   },
 
   data() {
     return {
-      uploading: false,
-      percentage: 0,
-      uploadedFiles: [],
-      filename: '',
-      success: false,
       dragOver: false,
-      draging: false,
-      mouseover: false,
-      tempIndex: 1
+      mouseover: false
     };
   },
 
   computed: {
-    uploadComponent() {
-      return typeof FormData !== 'undefined' ? 'AjaxUpload' : 'IframeUpload';
+    lastestFile() {
+      var uploadedFiles = this.$parent.uploadedFiles;
+      return uploadedFiles.length > 0 ? uploadedFiles[uploadedFiles.length - 1] : {};
     },
-    image() {
-      return this.uploadedFiles.length > 0 ? this.uploadedFiles[this.uploadedFiles.length - 1] : {};
+    showThumbnail() {
+      var file = this.lastestFile;
+      return this.thumbnailMode && file.status && file.status !== 'fail';
     },
-    showImageBlock() {
-      return this.mode === 'image' && this.image.status && this.image.status !== 'fail';
-    }
-  },
-
-  ready() {
-    if (this.mode === 'image') {
-      this.accept = 'image/*';
+    thumbnailMode() {
+      return this.$parent.thumbnailMode;
     }
   },
 
@@ -189,59 +105,76 @@ export default {
     isImage(str) {
       return str.indexOf('image') !== -1;
     },
-    removeFile(file) {
-      this.uploadedFiles.$remove(file);
-      this.$dispatch('fileremove', file, this.uploadedFiles);
+    handleChange(ev) {
+      const files = ev.target.files;
+
+      if (!files) {
+        return;
+      }
+      this.uploadFiles(files);
     },
-    onStart(files) {
-      files.forEach(file => {
-        let isImage = this.isImage(file.type);
-        let uid = Date.now() + this.tempIndex++;
-        let _file = {
-          status: 'uploading',
-          name: file.name,
-          size: file.size,
-          percentage: 0,
-          uid: uid
-        };
-        if (this.mode === 'image') {
-          if (!isImage) {
-            this.tempIndex--;
-            return;
-          } else {
-            _file.url = URL.createObjectURL(file);
-          }
-        }
+    uploadFiles(files) {
+      let postFiles = Array.prototype.slice.call(files);
+      if (!this.multiple) { postFiles = postFiles.slice(0, 1); }
+
+      if (postFiles.length === 0) { return; }
 
-        this.uploadedFiles.push(_file);
+      postFiles.forEach(file => {
+        let isImage = this.isImage(file.type);
 
-        file.index = this.uploadedFiles.length - 1;
+        if (this.thumbnailMode && !isImage) {
+          return;
+        } else {
+          this.upload(file);
+        }
       });
     },
-    onProgress(ev, file) {
-      this.uploadedFiles[file.index].percentage = ev.percent;
-    },
-    onSuccess(res, file) {
-      var _file = this.uploadedFiles[file.index];
+    upload(file) {
+      if (!this.beforeUpload) {
+        return this.post(file);
+      }
 
-      _file.status = 'success';
-      setTimeout(() => {
-        _file.status = 'finished';
-        this.reset();
-      }, 1000);
+      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);
+      }
     },
-    onError(err, file) {
-      var _file = this.uploadedFiles[file.index];
-
-      _file.status = 'finished';
-      this.uploadedFiles.$remove(_file);
-      this.reset();
-      console.log(err);
+    post(file) {
+      this.onStart(file);
+      let formData = new FormData();
+      formData.append(this.name, file);
+
+      ajax(this.action, {
+        headers: this.headers,
+        withCredentials: this.withCredentials,
+        file: file,
+        filename: this.name,
+        onProgress: e => {
+          this.onProgress(e, file);
+        },
+        onSuccess: res => {
+          this.onSuccess(res, file);
+        },
+        onError: err => {
+          this.onError(err, file);
+        }
+      });
     },
-    reset() {
-      this.uploading = false;
-      this.percent = 0;
-      this.filename = '';
+    onDrop(e) {
+      this.dragOver = false;
+      this.uploadFiles(e.dataTransfer.files);
     }
   }
 };