diff --git a/src/components/Upload/SingleImage.vue b/src/components/Upload/SingleImage.vue
new file mode 100644
index 00000000..ecec20a9
--- /dev/null
+++ b/src/components/Upload/SingleImage.vue
@@ -0,0 +1,135 @@
+<template>
+  <div class="upload-container">
+    <el-upload
+      :data="dataObj"
+      :multiple="false"
+      :show-file-list="false"
+      :on-success="handleImageSuccess"
+      class="image-uploader"
+      drag
+      action="https://httpbin.org/post"
+    >
+      <i class="el-icon-upload" />
+      <div class="el-upload__text">
+        将文件拖到此处,或<em>点击上传</em>
+      </div>
+    </el-upload>
+    <div class="image-preview">
+      <div v-show="imageUrl.length>1" class="image-preview-wrapper">
+        <img :src="imageUrl+'?imageView2/1/w/200/h/200'">
+        <div class="image-preview-action">
+          <i class="el-icon-delete" @click="rmImage" />
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+// 预览效果见付费文章
+import { getToken } from '@/api/qiniu'
+
+export default {
+  name: 'SingleImageUpload',
+  props: {
+    value: {
+      type: String,
+      default: ''
+    }
+  },
+  data() {
+    return {
+      tempUrl: '',
+      dataObj: { token: '', key: '' }
+    }
+  },
+  computed: {
+    imageUrl() {
+      return this.value
+    }
+  },
+  methods: {
+    rmImage() {
+      this.emitInput('')
+    },
+    emitInput(val) {
+      this.$emit('input', val)
+    },
+    handleImageSuccess() {
+      this.emitInput(this.tempUrl)
+    },
+    beforeUpload() {
+      const _self = this
+      return new Promise((resolve, reject) => {
+        getToken().then(response => {
+          const key = response.data.qiniu_key
+          const token = response.data.qiniu_token
+          _self._data.dataObj.token = token
+          _self._data.dataObj.key = key
+          this.tempUrl = response.data.qiniu_url
+          resolve(true)
+        }).catch(err => {
+          console.log(err)
+          reject(false)
+        })
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+    @import "~@/styles/mixin.scss";
+    .upload-container {
+        width: 100%;
+        position: relative;
+        @include clearfix;
+        .image-uploader {
+            width: 60%;
+            float: left;
+        }
+        .image-preview {
+            width: 200px;
+            height: 200px;
+            position: relative;
+            border: 1px dashed #d9d9d9;
+            float: left;
+            margin-left: 50px;
+            .image-preview-wrapper {
+                position: relative;
+                width: 100%;
+                height: 100%;
+                img {
+                    width: 100%;
+                    height: 100%;
+                }
+            }
+            .image-preview-action {
+                position: absolute;
+                width: 100%;
+                height: 100%;
+                left: 0;
+                top: 0;
+                cursor: default;
+                text-align: center;
+                color: #fff;
+                opacity: 0;
+                font-size: 20px;
+                background-color: rgba(0, 0, 0, .5);
+                transition: opacity .3s;
+                cursor: pointer;
+                text-align: center;
+                line-height: 200px;
+                .el-icon-delete {
+                    font-size: 36px;
+                }
+            }
+            &:hover {
+                .image-preview-action {
+                    opacity: 1;
+                }
+            }
+        }
+    }
+
+</style>
diff --git a/src/components/Upload/SingleImage2.vue b/src/components/Upload/SingleImage2.vue
new file mode 100644
index 00000000..07637a9e
--- /dev/null
+++ b/src/components/Upload/SingleImage2.vue
@@ -0,0 +1,130 @@
+<template>
+  <div class="singleImageUpload2 upload-container">
+    <el-upload
+      :data="dataObj"
+      :multiple="false"
+      :show-file-list="false"
+      :on-success="handleImageSuccess"
+      class="image-uploader"
+      drag
+      action="https://httpbin.org/post"
+    >
+      <i class="el-icon-upload" />
+      <div class="el-upload__text">
+        Drag或<em>点击上传</em>
+      </div>
+    </el-upload>
+    <div v-show="imageUrl.length>0" class="image-preview">
+      <div v-show="imageUrl.length>1" class="image-preview-wrapper">
+        <img :src="imageUrl">
+        <div class="image-preview-action">
+          <i class="el-icon-delete" @click="rmImage" />
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getToken } from '@/api/qiniu'
+
+export default {
+  name: 'SingleImageUpload2',
+  props: {
+    value: {
+      type: String,
+      default: ''
+    }
+  },
+  data() {
+    return {
+      tempUrl: '',
+      dataObj: { token: '', key: '' }
+    }
+  },
+  computed: {
+    imageUrl() {
+      return this.value
+    }
+  },
+  methods: {
+    rmImage() {
+      this.emitInput('')
+    },
+    emitInput(val) {
+      this.$emit('input', val)
+    },
+    handleImageSuccess() {
+      this.emitInput(this.tempUrl)
+    },
+    beforeUpload() {
+      const _self = this
+      return new Promise((resolve, reject) => {
+        getToken().then(response => {
+          const key = response.data.qiniu_key
+          const token = response.data.qiniu_token
+          _self._data.dataObj.token = token
+          _self._data.dataObj.key = key
+          this.tempUrl = response.data.qiniu_url
+          resolve(true)
+        }).catch(() => {
+          reject(false)
+        })
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.upload-container {
+  width: 100%;
+  height: 100%;
+  position: relative;
+  .image-uploader {
+    height: 100%;
+  }
+  .image-preview {
+    width: 100%;
+    height: 100%;
+    position: absolute;
+    left: 0px;
+    top: 0px;
+    border: 1px dashed #d9d9d9;
+    .image-preview-wrapper {
+      position: relative;
+      width: 100%;
+      height: 100%;
+      img {
+        width: 100%;
+        height: 100%;
+      }
+    }
+    .image-preview-action {
+      position: absolute;
+      width: 100%;
+      height: 100%;
+      left: 0;
+      top: 0;
+      cursor: default;
+      text-align: center;
+      color: #fff;
+      opacity: 0;
+      font-size: 20px;
+      background-color: rgba(0, 0, 0, .5);
+      transition: opacity .3s;
+      cursor: pointer;
+      text-align: center;
+      line-height: 200px;
+      .el-icon-delete {
+        font-size: 36px;
+      }
+    }
+    &:hover {
+      .image-preview-action {
+        opacity: 1;
+      }
+    }
+  }
+}
+</style>
diff --git a/src/components/Upload/SingleImage3.vue b/src/components/Upload/SingleImage3.vue
new file mode 100644
index 00000000..6300da4b
--- /dev/null
+++ b/src/components/Upload/SingleImage3.vue
@@ -0,0 +1,157 @@
+<template>
+  <div class="upload-container">
+    <el-upload
+      :data="dataObj"
+      :multiple="false"
+      :show-file-list="false"
+      :on-success="handleImageSuccess"
+      class="image-uploader"
+      drag
+      action="https://httpbin.org/post"
+    >
+      <i class="el-icon-upload" />
+      <div class="el-upload__text">
+        将文件拖到此处,或<em>点击上传</em>
+      </div>
+    </el-upload>
+    <div class="image-preview image-app-preview">
+      <div v-show="imageUrl.length>1" class="image-preview-wrapper">
+        <img :src="imageUrl">
+        <div class="image-preview-action">
+          <i class="el-icon-delete" @click="rmImage" />
+        </div>
+      </div>
+    </div>
+    <div class="image-preview">
+      <div v-show="imageUrl.length>1" class="image-preview-wrapper">
+        <img :src="imageUrl">
+        <div class="image-preview-action">
+          <i class="el-icon-delete" @click="rmImage" />
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getToken } from '@/api/qiniu'
+
+export default {
+  name: 'SingleImageUpload3',
+  props: {
+    value: {
+      type: String,
+      default: ''
+    }
+  },
+  data() {
+    return {
+      tempUrl: '',
+      dataObj: { token: '', key: '' }
+    }
+  },
+  computed: {
+    imageUrl() {
+      return this.value
+    }
+  },
+  methods: {
+    rmImage() {
+      this.emitInput('')
+    },
+    emitInput(val) {
+      this.$emit('input', val)
+    },
+    handleImageSuccess(file) {
+      this.emitInput(file.files.file)
+    },
+    beforeUpload() {
+      const _self = this
+      return new Promise((resolve, reject) => {
+        getToken().then(response => {
+          const key = response.data.qiniu_key
+          const token = response.data.qiniu_token
+          _self._data.dataObj.token = token
+          _self._data.dataObj.key = key
+          this.tempUrl = response.data.qiniu_url
+          resolve(true)
+        }).catch(err => {
+          console.log(err)
+          reject(false)
+        })
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import "~@/styles/mixin.scss";
+.upload-container {
+  width: 100%;
+  position: relative;
+  @include clearfix;
+  .image-uploader {
+    width: 35%;
+    float: left;
+  }
+  .image-preview {
+    width: 200px;
+    height: 200px;
+    position: relative;
+    border: 1px dashed #d9d9d9;
+    float: left;
+    margin-left: 50px;
+    .image-preview-wrapper {
+      position: relative;
+      width: 100%;
+      height: 100%;
+      img {
+        width: 100%;
+        height: 100%;
+      }
+    }
+    .image-preview-action {
+      position: absolute;
+      width: 100%;
+      height: 100%;
+      left: 0;
+      top: 0;
+      cursor: default;
+      text-align: center;
+      color: #fff;
+      opacity: 0;
+      font-size: 20px;
+      background-color: rgba(0, 0, 0, .5);
+      transition: opacity .3s;
+      cursor: pointer;
+      text-align: center;
+      line-height: 200px;
+      .el-icon-delete {
+        font-size: 36px;
+      }
+    }
+    &:hover {
+      .image-preview-action {
+        opacity: 1;
+      }
+    }
+  }
+  .image-app-preview {
+    width: 320px;
+    height: 180px;
+    position: relative;
+    border: 1px dashed #d9d9d9;
+    float: left;
+    margin-left: 50px;
+    .app-fake-conver {
+      height: 44px;
+      position: absolute;
+      width: 100%; // background: rgba(0, 0, 0, .1);
+      text-align: center;
+      line-height: 64px;
+      color: #fff;
+    }
+  }
+}
+</style>
diff --git a/src/views/example/components/ArticleDetail.vue b/src/views/example/components/ArticleDetail.vue
index d9d71664..58574ab0 100644
--- a/src/views/example/components/ArticleDetail.vue
+++ b/src/views/example/components/ArticleDetail.vue
@@ -76,7 +76,7 @@
 
 <script>
 import Tinymce from '@/components/Tinymce'
-import Upload from '@/components/Upload/singleImage3'
+import Upload from '@/components/Upload/SingleImage3'
 import MDinput from '@/components/MDinput'
 import Sticky from '@/components/Sticky' // 粘性header组件
 import { validURL } from '@/utils/validate'