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);