[React Component Encapsulation] [Instance] File Selection Button Component Encapsulation

Public Number: Programmer Bobo

File selector is often used by us, usually by clicking a button and then selecting the file.

So it is necessary to encapsulate a file selection button.

First, the button must be exactly the same as the ordinary button, otherwise it will lose the meaning of encapsulation.

Secondly, it should basically conform to the points mentioned in my [foundation].

So (note that using image /* in chrome is slow):(base version)

import React, { PureComponent } from 'react';
import CSSModules from 'react-css-modules';

import Tools from '../../common_js/Tools'

import styles from './FileButton.css'

class FileButton extends PureComponent {
    constructor(props) {
        super(props);

        this.getFiles = this.getFiles.bind(this)
        this.onChange = this.onChange.bind(this)
    }

    getFiles() {
        let ans = []
        let files = this.refs.fileLoader.files
        for (let i = 0; i < files.length; i++) {
            ans.push(files[i])
        }
        return ans
    }

    onChange(e) {
        if (!Tools.isNone(this.props.onChange)) {
            this.props.onChange(this.getFiles())
        }
        this.refs.fileLoader.value = ''
    }

    render() {
        let accept = this.props.accept
        if (Tools.isNone(accept)) {
            accept = 'image/*'
            if (Tools.isChrome()) {
                accept = 'image/jpeg,image/gif,image/png,image/bmp'
            }
        }
        return (
            <label className={this.props.className} style={this.props.style} >
                {this.props.children}
                {
                    this.props.multiple == true ?
                        <input styleName='input-area' ref='fileLoader' onChange={this.onChange} type="file" accept={accept} multiple />
                    :
                        <input styleName='input-area' ref='fileLoader' onChange={this.onChange} type="file" accept={accept} />
                }
            </label>
        );
    }
}

export default CSSModules(FileButton, styles);

input_area style:

.input-area {
    width: 0px;
    height: 0px;
    position:absolute;
    clip:rect(0 0 0 0);
}

In addition: (@material-ui encapsulated version of Button)

import React, { PureComponent } from 'react';
import CSSModules from 'react-css-modules';

import Button from '@material-ui/core/Button';
import Tools from '../../../common_js/Tools'

import styles from './FileButton.css'

class FileButton extends PureComponent {
    constructor(props) {
        super(props);

        this.getFiles = this.getFiles.bind(this)
        this.onChange = this.onChange.bind(this)
    }

    getFiles() {
        let ans = []
        let files = this.refs.fileLoader.files
        for (let i = 0; i < files.length; i++) {
            ans.push(files[i])
        }
        return ans
    }

    onChange(e) {
        if (!Tools.isNone(this.props.onChange)) {
            this.props.onChange(this.getFiles())
        }
        this.refs.fileLoader.value = ''
    }

    render() {
        let {accept, onChange, children, multiple, ...other} = this.props
        if (Tools.isNone(accept)) {
            accept = 'image/*'
            if (Tools.isChrome()) {
                accept = 'image/jpeg,image/gif,image/png,image/bmp'
            }
        }

        return (
            <Button component='label' {...other} >
                {
                    this.props.multiple == true ?
                        <input styleName='input-area' ref='fileLoader' onChange={this.onChange} type="file" accept={accept} multiple />
                    :
                        <input styleName='input-area' ref='fileLoader' onChange={this.onChange} type="file" accept={accept} />
                }
                {this.props.children}
            </Button>
        );
    }
}

export default CSSModules(FileButton, styles);

 

Keywords: React

Added by ernielou on Wed, 02 Oct 2019 04:04:56 +0300