封装Vue Element的upload上传组件

原本昨天就想分享封装的这个upload组件,结果刚写了两句话,就被边上的同事给偷窥上了,因而在我全神贯注地写分享的时候,他就神不知鬼不觉地忽然移动到我身边,腆着脸问我在干啥呢。卧槽你妈,当场就把我吓了一跳,我说我没干吗,在工做啊,而后我就把浏览器窗口切换了,他就来了一句:我看到了博客。我没搭理他,但内心就不停地在骂“槽你妈”,我确实很生气。其实我一直很反感那种坐在你边上有事没事就斜眼瞄你的电脑屏幕的同事,那种上班期间被偷窥的感受很不爽。我这么说不是我特地去注意旁边的同事有没有在斜眼偷瞄个人电脑屏幕,由于我忙起来,我TM连我边上有没有人都不会有感受的,之因此会常常发现被旁边的同事偷瞄,是由于工做时间久了,个人颈椎会很疼,头也疼,腰也很难受,因此我就会抬头仰望天花板或“葛优躺”靠在椅背上,这时个人眼睛余光就能很明确地感受到个人电脑屏幕正在被旁边的同事偷瞄,我又不是那种直接回望过去:你TM的偷瞄什么呢?卧槽TM的,我就一直很奇怪,为何我会常常跟那种喜欢偷瞄别人工做的人坐在一块儿,我也一直很奇怪,那种喜欢偷瞄别人工做或偷瞄别人电脑屏幕的人都是什么心理。但凡我发现个人电脑屏幕或我正在工做时被别人偷瞄,我就很不爽,浑身不自在,不知道你们有没有碰到这样的同事。html

一直都很忙,写分享基本都是在中午午休时赶出来的,而后趁着在工做中颈椎疼的难以忍受时稍微休息一下的过程当中排版发出来的。不过我也发现一个现象,就是我分享的有关封装的react方面的组件的关注度没有封装的vue方面的组件的关注度来得高,有多是百度对我分享的vue方面的组件作了收录,因此你们也能在百度上搜索到,而我分享的react方面的组件却基本没有被百度收录的缘由,或许也有多是用vue的人多过用react的人,但我无心去对比二者,你们开心就好。vue

今天写的这个upload组件也是采用的函数式组件,而后结合着Element ui的上传组件来封装,接下来就看具体实现吧。react

仍是先来一张效果图:

一、封装的上传组件Upload.js面试

import { Message } from 'element-ui'
let OSS = require("ali-oss");

const SUFFIX = /.+(\.\w+)$/,
  TIMEOUT = 60000,
  BYTE = 1024,
  RETRY_COUNT_MAX = 3,
  ACCEPT = {
    zip: 'application/zip,application/x-zip,application/x-zip-compressed',
    pdf: 'application/pdf',
    excel: 'application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    image: 'image/jpeg,image/bmp,image/png,image/gif',
  },
  getAccepts = accept => (Array.isArray(accept) ? accept : [accept]).map(ac => ACCEPT[ac]).join(','),
  beforeCheck = (config, file) => {
    let {max = Number.MAX_VALUE, accept = []} = config || {}, { size, type } = file, accepts = getAccepts(accept).split(',');
    
    //大小限制(M)
    if(Math.pow(BYTE, 2) * max < size){
        Message.warning(`文件不能超过${max}M`);
        return false;
    }
  };

export default {
  functional: true,
  props: {config: Object, limit: Number, percentage: Function},
  render: (h, ctx) => {
    let {props, data: attrs, parent: {$store: { dispatch}}, children} = ctx, { config, limit } = props, retryCount = 0, { accept } = config;
    if(!attrs.attrs.accept && accept){
      attrs.attrs.accept = getAccepts(accept);
    }

    Object.assign(props, {
      action: '',
      beforeUpload: file => beforeCheck(config, file),
      onExceed: () => Message.warning(`最多能够上传${limit}个文件`),
      httpRequest: opts => {
        let { file, onError, onProgress, onSuccess } = opts, { uid, name, type } = file;
        name = `${uid}${name.replace(SUFFIX, '$1')}`;
        if(getAccepts(accept).indexOf(type) > -1) file.isImg = true

        dispatch('getClient').then(res => {
          let aliClient = new OSS(res), { path } = res, url = path + '/' + name;
          //multipartUpload是阿里云的分片(分段)大文件上传方法,这里也能够用put方法来上传单个小文件(aliClient.put)
          aliClient.multipartUpload(url, file, {
            timeout: TIMEOUT,
            partSize: 500 * BYTE,
            progress: p => {
              onProgress(p * 100, file)
            }
          }).then(r => {
            let { res: { requestUrls } } = r;
            requestUrls = requestUrls.length < 1 ? '' : requestUrls[0]
            if (requestUrls.indexOf('?') > -1) requestUrls = requestUrls.split('?')[0]
            onSuccess({ res: file, url: requestUrls });
          }).catch(err => {
            let { name } = err;
            if (aliClient.isCancel()) {
              console.log('stop-upload!');
            } else {
              Message.error(err);
              onError(err);
              if (name.toLowerCase().indexOf('connectiontimeout') !== -1) {
                if (retryCount < RETRY_COUNT_MAX) {
                  retryCount++;
                  props.httpRequest(opt)
                }
              }
            }
          });;
        })
      }
    })
    return h('el-upload', {props, ...attrs}, children)
  }
}

本次封装的upload上传组件的封装方式和实现的功能与以前我所分享的封装React AntD的upload上传组件相似,你能够移步到那篇文章去详细了解,这里再也不赘述。element-ui

另外,咱们公司所上传的文件都是上传到了阿里云,因此这里顺带着将上传到阿里云的方法也给粗略地实现了。上传到阿里云所用到的API请自行查阅,本次分享也再也不赘述。数组

二、使用方法:浏览器

<template>
  <div class="container">
    <p>第一种上传形式:</p>
    <Upload :limit="limit" :on-success="onSuccess" :config="config" :on-progress="onProgress" :on-preview="onPreview" :on-remove="onRemove" list-type="picture-card">
      <i class="el-icon-plus"></i>
    </Upload>
    <br />
    <p>第二种上传形式:</p>
    <Upload :limit="limit" :on-success="onSuccess" :config="config" :on-progress="onProgress" :on-preview="onPreview" :on-remove="onRemove">
      <el-button size="small" type="primary">点击上传</el-button>
    </Upload>
  </div>
</template>

<script>
import Upload from '@/components/Upload'

export default {
  components: {
    Upload,
  },
  data() {
    return {
      limit: 1,
      config: {
        accept: "image", //接受上传的文件类型:zip、pdf、excel、image,也能够是文件类型所组成的数组类型如:['image', 'pdf'],则只能够上传图片或pdf类型的文件,也能够为空,则任何类型的文件均可以上传
        max: 100, //文件大小
      },
      fileList: [],
    }
  },
  methods: {
    //文件上传完成后的回调
    onSuccess({res: {uid, isImg}, url}) {
      this.fileList.push({uid, url})
    },
    //文件上传进度条
    onProgress(percent, file){

    },
    //上传文件
    onRemove(file){
      this.fileList = this.fileList.filter(n => n.uid != file.uid)
    },
  },
}
</script>

之前去面试的时候,常常会有面试官问我在开发的过程当中有没有本身封装过组件,我说封装过,而后面试官就让我举例,那时候个人回答通常都不是基于函数式的封装,都仍是带有状态和生命周期函数的那种封装,但面试官也没说啥。后来接触到函数式组件,才以为这玩意儿是真好使。app

PS:刚才发现我边上那个同事在用挖耳勺掏耳朵的时候还在偷瞄的电脑屏幕,册那!函数