zoukankan      html  css  js  c++  java
  • 封装React AntD的upload上传组件

    上传文件也是我们在实际开发中常遇到的功能,比如上传产品图片以供更好地宣传我们的产品,上传excel文档以便于更好地展示更多的产品信息,上传zip文件以便于更好地收集一些资料信息等等。至于为何要把上传组件封装成一个公共的、可复用的组件,在前两篇文章封装react antd的form表单组件封装react antd的表格table组件中已经作了很多介绍,这里同样不再赘述。

    有朋友觉得这些功能组件在各种前端框架满天飞的今天都大同小异、大差不差,甚至觉得Level有点Low。哈哈,其实事实也确实是这样的,我们去二次封装这些原本已基本成熟的框架组件,逼格也确实不高,且随心所欲的空间也不大,但我觉得这并不妨碍我们的日常开发。我们作为前端er,大部分工作都是在产品er的需求阴影下,顶着发际线越来越高的蒙圈脑袋,认认真真的砌墙,在胆战心惊、如履薄冰地试探“今晚会否加班”的心态中活过每一个白天,已经是阿弥陀佛了。如果再碰上一个好的领导,在每一个阶段的开发任务结束后能再请我们去嗨皮一番,那就真是“今天好天气,老狼请吃鸡了。” 所以,我们能做的,只有简化开发步骤,提高组件的复用率,再完美一点就是提供可定制化的封装组件了。但这是个仁者见仁智者见智的看法,我还是很尊重认可有独立思考能力的人!

    话不多说,先来介绍一下封装过程中所关注的几个点:

    • 上传文件的大小

    上传文件势必需要我们去关注所上传文件的大小。这个功能点,我们放在antd所提供的upload组件的beforeUpload方法中,当然beforeUpload方法我们也是封装在upload组件中,通过使用时传入的配置来控制文件大小。

    • 上传文件的格式或类型

    上传文件的格式或类型也是我们必须要去关注的一个点,比如这个上传控件只能上传图片,那个上传控件只能上传excel文档等等,我们可以使用antd所提供的upload组件的accept来控制,当然accept也是被封装在了upload组件中。

    • 自定义上传的方法

    antd所提供的upload组件中给我们提供了一个action的API,官方的解释是action:上传的地址,跟form的表单提交有点类似。这种的上传方式我们不太好控制,我们会使用upload组件的customRequest方法来自定义上传的实现,官方对其的解释是:通过覆盖默认的上传行为,可以自定义自己的上传实现。

    关于上传功能,我们需要注意的也基本就是以上三点,至于我们是上传到自己的服务器还是第三方如阿里云,则不在这篇文章的介绍范围了。下面来看一下具体实现。

    外甥打灯笼——照舅(照旧)先放一张效果图:

    效果图有点小,因为是缩略图,就不要介意这个细节了。
    1、所封装的上传组件upload.js

    import { createElement } from 'react'
    import { Upload, message } from 'antd';
    
    const h = createElement;
    
    const SUFFIX = /.+(.w+)$/,
          BYTE = 1024,
          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 { accept, max = Number.MAX_VALUE } = config || {}, { size, type } = file, accepts = getAccepts(accept).split(',');
            //大小限制(M)
            if(Math.pow(BYTE, 2) * max < size){
              message.info(`文件不能超过${max}M`);
              return false;
            }
          }
    
    const UploadComponent = props => {
      let { children, config } = props, { accept } = config, attrs = {};
      //不能在props对象上直接添加属性,只能再定义一个attrs对象
      Object.assign(attrs, {
        action: '',
        accept: getAccepts(accept),
        beforeUpload: file => beforeCheck(config, file),
        customRequest: opts => {
          let { file, onSuccess, onProgress, onError } = opts, { uid, name, type } = file;
          name = `${uid}${name.replace(SUFFIX, '$1')}`;
          //判断上传的文件是否是图片,若不是图片,前端可自行根据isImg来控制是否可预览文件
          if(getAccepts(accept).indexOf(type) > -1) file.isImg = true
    
          // fetch('https://jsonplaceholder.typicode.com/posts', {
          //   method: 'POST',
          //   body: 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 });
          // })
    
          let resFile = {
            uid,
            name,
            url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
          }
    
          onSuccess(resFile)
        },
      })
    
      return h(Upload, {...props, ...attrs}, children)
    }
    
    export default UploadComponent
    

    代码中注释的部分模拟的就是上传到服务器,不过这个地址是从antd上抄来的,貌似不能用。

    2、upload组件的使用方法:

    import React, { useState } from 'react'
    import Upload from './Upload'
    
    const UploadComp = () => {
      const config = {
        accept: 'image',   //接受上传的文件类型:zip、pdf、excel、image,也可以是文件类型所组成的数组类型如:['image', 'pdf'],则只可以上传图片或pdf类型的文件,也可以为空,则任何类型的文件都可以上传
        max: 1,    //限制上传文件大小
      };
    
      const [fileList, setFileList] = useState([])
    
      const onPreview = file => {
        console.log(file)
      }
    
      const onSuccess = res => {
        //useState不能向数组中push数据,只能通过这样的方式来push数据
        setFileList([...fileList, res])
      }
    
      return <Upload listType="picture-card" config={config} fileList={fileList} onSuccess={onSuccess} onPreview={onPreview}>{fileList.length >= 2 ? null : '上传'}</Upload>
    }
    
    export default UploadComp
    

    对于封装的这个upload组件,还有一点想说的就是我只是按照antd的API做了封装,然后再把这些API传递给upload组件。如果你说我想把上传两个字给成按钮形式的可以吗?当然可以,只要antd是如何做到的,我这里就也是如何做到的。所以参照antd的官方实现方法即可。至于其他配置,如果你有实际需求,再往组件中添加就行了。

    最后还是再贴一下本次封装所用到的各个包的版本:

    react: 16.8.6,

    react-dom: 16.8.6,

    react-router-dom: 5.0.0,

    antd: 4.3.5,

    @babel/core: 7.4.4,

    babel-loader: 8.0.5

  • 相关阅读:
    剑指Offer 30 包含min函数的栈
    剑指Offer 29 顺时针打印矩阵
    剑指Offer 27 二叉树的镜像
    13张动图助你彻底看懂马尔科夫链、PCA和条件概率!
    一位ML工程师构建深度神经网络的实用技巧
    IBM沃森会成为第一个被抛弃的AI技术吗?
    中国最强AI超级服务器问世,每秒提供AI计算2000万亿次
    SAP WM 有无保存WM Level历史库存的Table?
    SAP MM 按采购订单查询付款信息的报表?
    机器学习项目失败的9个原因
  • 原文地址:https://www.cnblogs.com/tnnyang/p/13503523.html
Copyright © 2011-2022 走看看