封裝 antd-upload

剛到杭州感覺略疲憊,后臺大佬(世界上最好的語言的使用者)表示我們的上傳圖片要做成前端直接上傳七牛,然后把地址給后端。。。。emmm 原來最優(yōu)秀的后臺都會偷懶啊。

那我只能基于antd的upload封裝出一個比較適用于圖片上傳七牛,oss,后臺的組件了,這是 antd-upload地址

剛學(xué)會hooks并且應(yīng)用于自己的項目,瞎子過河摸索著過唄
    import React, { useEffect, useState } from 'react';

    const [qiNiuToken, setQiNiuToken] = useState(null);

    const qiniuAction = 'http://upload.qiniup.com';

    const normFile = info => {  // 將upload的值作為裝飾器的value

        return (info.file && info.file.response) || undefined;

    }

    useEffect(() => {  // 這里是在didmount和qiNiuToken改變的時候 重新去嘗試請求新的qiniu toekn

        if (qiNiuToken) return;

        const asyncRequest = async () => {

            const token = await appApi.receiveQiniuToken();

            setQiNiuToken(token);

        }

        asyncRequest();

    }, [qiNiuToken])

    const onUploadEnd = () => { // 這里是在圖片上傳之后 調(diào)用此函數(shù)將qiNiuToken改變 以觸發(fā)重新請求
        setQiNiuToken(null);
    }
  <FormItem>
       <Text><Text type="danger">*</Text>主辦單位證件</Text>
          {
             getFieldDecorator(
                'cert', {
                   valuePropName: 'file',
                   getValueFromEvent: normFile,
                   rules: [
                    {
                       required: true,
                       message: '請上傳主辦單位證件!'
                     }
                    ]
                }
              )(
               <CustomUpload
                 className="icbc-legal-upload"
                 placeholder="請上傳營業(yè)執(zhí)照或三證合一掃描件"
                 action={qiniuAction}
                 data={
                        {
                          token: qiNiuToken
                        }
                 }
                 onUploadEnd={onUploadEnd}
               />
        )
     }
</FormItem>
接下來是重頭戲 組件
  // 因為Form裝飾器getFieldDecorator的某些屬性不支持函數(shù)組件 這里使用類組件的形式
import React, { Component } from 'react';

import { Upload, Icon, message, Modal } from 'antd';

// 圖片轉(zhuǎn)換base64   以及上傳前的檢測
import { getBase64, filterPic } from 'lib/utils';

import './index.scss';

class CustomUpload extends Component {
    // imageUrl 是上傳圖片后轉(zhuǎn)base64在頁面中的顯示
    // previewVisible 查看大圖的開關(guān)
    // showMask 自己寫的上傳圖片后的mask  可以查看大圖以及刪除圖片
    constructor(props) {
        super(props);
        this.state = {
            imageUrl: '',
            loading: false,
            previewVisible: false,
            showMask: false
        }
    }
    /**
     * export const filterPic = pic => {
            let content = '';
            const isJpgOrPng = pic.type === 'image/jpeg' || pic.type === 'image/png';
            if (!isJpgOrPng) {
                content = ' 請上傳JPG/PNG文件!';
            }
            const isLt2M = pic.size / 1024 / 1024 < 10;
            if (!isLt2M) {
                content = '圖像必須小于10MB!';
            }
            return content;
        }
     */
    // 上傳圖片之前對圖片進行檢測  大小 類型
    beforeUpload = file => {
        const content = filterPic(file);
        if (content) {
            message.error(content);
            return false;
        }
        return true;
    }
    // 處理上傳中的步驟 done 為上傳完成
    handleChange = (info, callback) => {
        if (info.file.status === 'uploading') {
            this.setState({ loading: true });
            return;
        }
        if (info.file.status === 'done') {
            const { onUploadEnd } = this.props;
            onUploadEnd(); // 上傳完成后通知父組件 可以做刷新七牛token的操作
            callback&&callback(info);// 這里由于要將請求的結(jié)果作為getFieldDecorator裝飾器的value 調(diào)用傳入的callback 實際調(diào)用的就是getValueFromEvent
            getBase64(info.file.originFileObj, imageUrl => {
                this.setState({
                    imageUrl,
                    loading: false
                })
            });
        }
    };
    onMouseEnter = () => { // 自己寫的一些動畫 略簡陋
        const { imageUrl } = this.state;
        if (imageUrl) {
            this.setState({
                showMask: true
            })
        }
    }
    onMouseLeave = () => {
        this.setState({
            showMask: false
        })
    }
    handlePreview = file => {  // 查看大圖
        this.setState({
            previewVisible: true
        });
    };
    handleDelete = () => { // 刪除圖片
        const { onChange } = this.props;
        Modal.confirm({
            title: '提示',
            content: '確定要刪除此圖片?',
            okText: '確定',
            cancelText: '取消',
            onOk: () => {
                this.setState({
                    imageUrl: false
                }, () => {
                    onChange({}) //刪掉裝飾器里的val
                });
            }
        });

    }
    // 取消查看大圖
    handleCancel = () => this.setState({ previewVisible: false });

    render() {
        // data 此次請求攜帶的參數(shù)  傳七牛需要帶token  由父組件傳入  action  hostapi
        const { className, placeholder, onChange, data = {}, action } = this.props;

        const { loading, imageUrl, previewVisible, showMask } = this.state;

        return (
            <div className="upload-main" onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
                <div className={`mask ${showMask ? 'showMask' : ''}`}>
                    <Icon type="eye" onClick={this.handlePreview} />
                    <Icon type="delete" onClick={this.handleDelete} />
                </div>
                <Upload
                    listType="picture-card"
                    className={`uploader ${className}`}
                    showUploadList={false}
                    action={action}
                    data={data}
                    beforeUpload={this.beforeUpload}
                    onChange={info => this.handleChange(info, onChange)}
                >
                    {
                        imageUrl ? <img src={imageUrl} alt="pic" style={{ width: '100%', height: '100%' }} /> : <div>
                            <Icon type={loading ? 'loading' : 'plus'} />
                            <div className="ant-upload-text">{placeholder || 'Upload'}</div>
                        </div>
                    }

                </Upload>
                <Modal visible={previewVisible} footer={null} onCancel={this.handleCancel} width={600}>
                    <img alt="example" src={imageUrl} style={{ maxWidth: '100%' }} />
                </Modal>
            </div>
        )
    }
}
export default CustomUpload;

index.scss 送給連樣式都懶得寫的你
  .upload-main{
    position: relative;
    width: 300px;
    height: 202px;
    .mask{
        position: absolute;
        left: 0;
        top: 0;
        right: 0;
        bottom: 0;
        background: #000;
        opacity: 0;
        transition: all .3s;
        visibility: hidden;
        display: flex;
        justify-content: center;
        align-items: center;
        &.showMask{
            opacity: .4;
            visibility: visible;
            .anticon{
                cursor: pointer;
                margin-right: 10px;
                font-size: 20px;
                color: #fff;
            }
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容