封裝react antd的upload上傳組件

上傳文件也是咱們在實際開發中常遇到的功能,好比上傳產品圖片以供更好地宣傳咱們的產品,上傳excel文檔以便於更好地展現更多的產品信息,上傳zip文件以便於更好地收集一些資料信息等等。至於爲什麼要把上傳組件封裝成一個公共的、可複用的組件,在前兩篇文章封裝react antd的form表單組件封裝react antd的表格table組件中已經做了不少介紹,這裏一樣再也不贅述。html

有朋友以爲這些功能組件在各類前端框架滿天飛的今天都大同小異、大差不差,甚至以爲Level有點Low。哈哈,其實事實也確實是這樣的,咱們去二次封裝這些本來已基本成熟的框架組件,逼格也確實不高,且爲所欲爲的空間也不大,但我以爲這並不妨礙咱們的平常開發。咱們做爲前端er,大部分工做都是在產品er的需求陰影下,頂着髮際線愈來愈高的蒙圈腦殼,認認真真的砌牆,在膽戰心驚、如履薄冰地試探「今晚會否加班」的心態中活過每個白天,已是阿彌陀佛了。若是再碰上一個好的領導,在每個階段的開發任務結束後能再請咱們去嗨皮一番,那就真是「今天好天氣,老狼請吃雞了。」 因此,咱們能作的,只有簡化開發步驟,提升組件的複用率,再完美一點就是提供可定製化的封裝組件了。但這是個仁者見仁智者見智的見解,我仍是很尊重承認有獨立思考能力的人!前端

話很少說,先來介紹一下封裝過程當中所關注的幾個點:react

  • 上傳文件的大小

上傳文件勢必須要咱們去關注所上傳文件的大小。這個功能點,咱們放在antd所提供的upload組件的beforeUpload方法中,固然beforeUpload方法咱們也是封裝在upload組件中,經過使用時傳入的配置來控制文件大小。json

  • 上傳文件的格式或類型

上傳文件的格式或類型也是咱們必需要去關注的一個點,好比這個上傳控件只能上傳圖片,那個上傳控件只能上傳excel文檔等等,咱們可使用antd所提供的upload組件的accept來控制,固然accept也是被封裝在了upload組件中。數組

  • 自定義上傳的方法

antd所提供的upload組件中給咱們提供了一個action的API,官方的解釋是action:上傳的地址,跟form的表單提交有點相似。這種的上傳方式咱們不太好控制,咱們會使用upload組件的customRequest方法來自定義上傳的實現,官方對其的解釋是:經過覆蓋默認的上傳行爲,能夠自定義本身的上傳實現。前端框架

關於上傳功能,咱們須要注意的也基本就是以上三點,至於咱們是上傳到本身的服務器仍是第三方如阿里雲,則不在這篇文章的介紹範圍了。下面來看一下具體實現。服務器

外甥打燈籠——照舅(照舊)先放一張效果圖:

效果圖有點小,由於是縮略圖,就不要介意這個細節了。
一、所封裝的上傳組件upload.jsbabel

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上抄來的,貌似不能用。antd

二、upload組件的使用方法:react-router

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

相關文章
相關標籤/搜索