UNPKG

@6thquake/react-material

Version:

React components that implement Google's Material Design.

528 lines (473 loc) 12.6 kB
import React, { Component } from 'react'; import PropTypes from 'prop-types'; import Button from '../Button'; import withStyles from '../styles/withStyles'; import Chip from '../Chip'; import Paper from '../Paper'; import CancelIcon from '@material-ui/icons/Cancel'; import { DragDropContext } from 'react-dnd'; import HTML5Backend, { NativeTypes } from 'react-dnd-html5-backend'; import TargetBox from './TargetBox'; import isString from 'lodash/isString'; const styles = theme => ({ button: { margin: theme.spacing(1) }, input: { display: 'none' }, paper: { display: 'flex', justifyContent: 'center', flexWrap: 'wrap', borderRadius: '5px' }, chip: { margin: theme.spacing(0.5) }, wrap: { width: '160px', margin: '0 auto' }, choose: { display: 'inline-block' }, array: { display: 'flex', alignItems: 'center', justifyContent: 'center' }, inputImg: { opacity: '0', position: 'absolute', display: 'block', width: '140px', height: '140px' }, clickToUpload: { width: '144px', height: '110px', margin: '4px', border: '1px dashed #BDBDBD', backgroundColor: '#e0e0e0', textAlign: 'center', borderRadius: '16px', position: 'relative', display: 'inline-block' }, add: { fontSize: '30px', padding: '30px 0 0 0', color: '#616161' }, uploadText: { fontSize: '15px', color: '#000', padding: '10px 0 0 0' }, media: { height: '130px', width: '130px', position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%,-50%)', overflow: 'hidden', borderRadius: '5px', backgroundSize: 'cover', backgroundPosition: 'center' }, chipDrag: { height: '110px', margin: theme.spacing(0.5), padding: '0' }, dragToUpload: { minHeight: '300px', minWidth: '400px', border: '1px dashed #BDBDBD', backgroundColor: '#F5F5F5', textAlign: 'center', borderRadius: '5px', display: 'flex', flexWrap: 'wrap', justifyContent: 'center', alignItems: 'center' }, mediaDrag: { height: '100px', width: '100px', borderRadius: '10px', backgroundSize: 'cover', backgroundPosition: 'center' }, icon: { position: 'relative', top: '-40px' } }); var _ref = React.createElement("div", null, "type is not correct"); class Upload extends Component { constructor(props) { super(props); this.handleChangePath = e => { for (let i = 0; i < e.target.files.length; i += 1) { const file = e.target.files[i]; this.pathHandler(file); } }; this.handleDelete = (e, item) => { const { data, files } = this.state; let indexToDelete = files.indexOf(item); if (indexToDelete !== -1) { files.splice(indexToDelete, 1); } indexToDelete = data.indexOf(item); if (indexToDelete !== -1) { data.splice(indexToDelete, 1); } this.setState({ files: files.slice(), data: data.slice() }); if (this.props.onDelete) { this.props.onDelete(item); // delete item.preview; } /* type='drag',防止点击删除时弹出input框 */ if (e) { e.preventDefault(); } }; this.handleFileDrop = (item, monitor) => { if (monitor) { for (let i = 0; i < monitor.getItem().files.length; i++) { const file = monitor.getItem().files[i]; this.pathHandler(file); } } }; this.handleUpload = () => { const { data } = this.state; return this.props.upload(data); }; this.state = { data: [], files: [] }; } componentDidMount() { const { files } = this.props; if (files) { for (let i = 0; i < files.length; i += 1) { const file = files[i]; this.pathHandler(file); } } } componentDidUpdate(prevProps, prevState) { const { onChange } = this.props; if (prevState.data !== this.state.data) { onChange(this.state.data); } } /* 通过点击input标签添加图片 */ pathHandler(file) { if (!file) { return; } if (isString(file)) { file = { name: file, url: file }; } const { multiple } = this.props; if (this.state.files.indexOf(file) > -1) { return; } if (!multiple) { const { files } = this.state; if (files.length > 0) { for (let i = 0; i < files.length; i++) { this.handleDelete(null, files[i]); } } } if (file instanceof File) { this.setState(preState => ({ data: multiple ? [...preState.data, file] : [file] })); } if (/^image\/\S+$/.test(file.type)) { file.preview = React.createElement('img', { src: URL.createObjectURL(file), height: '100%', width: '100%', onLoad: e => { URL.revokeObjectURL(e.target.src); } }); this.setState(preState => ({ files: multiple ? [...preState.files, file] : [file] })); } else { if (!(file instanceof File)) { const url = file.url || file.name; if (/blob|http(s)?:\/\//.test(url)) { file.preview = React.createElement('img', { src: url, height: '100%', width: '100%' }); } } this.setState(preState => ({ files: multiple ? [...preState.files, file] : [file] })); } } render() { const { classes, type, multiple, disabled, label } = this.props; const { FILE } = NativeTypes; const { files } = this.state; let manual; let basic; let img; let drag; const id = `RM-UPLOAD-${new Date().getTime()}`; if (type === 'manual') { manual = React.createElement("div", null, React.createElement("div", { className: classes.wrap }, React.createElement("input", { accept: this.props.acceptType, ref: input => this.selectInput = input, className: classes.input, id: id, onChange: this.handleChangePath, type: "file", multiple: multiple, disabled: disabled }), React.createElement("label", { htmlFor: id }, this.props.children)), React.createElement(Paper, { className: classes.paper }, files.map(item => { return React.createElement(Chip, { key: item, label: item.name, onDelete: e => this.handleDelete(e, item), className: classes.chip, disabled: disabled }); })), React.createElement("div", { className: classes.wrap }, React.createElement(Button, { color: "primary", variant: "contained", className: classes.button, onClick: this.handleUpload, disabled: disabled }, label))); } if (type === 'basic') { basic = React.createElement("div", null, React.createElement("div", { className: classes.choose }, React.createElement("input", { accept: this.props.acceptType, ref: input => this.selectInput = input, className: classes.input, id: id, onChange: this.handleChangePath, type: "file", multiple: multiple, disabled: disabled }), React.createElement("label", { htmlFor: id }, this.props.children)), React.createElement("div", { className: classes.array }, files.map(item => { return React.createElement(Chip, { key: item, label: item.name, onDelete: e => this.handleDelete(e, item), className: classes.chip, disabled: disabled }); }))); } if (type === 'img') { img = React.createElement("div", null, React.createElement("input", { accept: "image/*", id: id, ref: input => this.selectInput = input, onChange: this.handleChangePath, type: "file", className: classes.inputImg, multiple: multiple, disabled: disabled }), React.createElement("label", { htmlFor: id }, React.createElement("div", { className: classes.array }, files.map(item => { const preview = React.createElement("div", { className: classes.mediaDrag // style={{ backgroundImage: 'url(' + content + ')' }} }, item.preview || item.name); return React.createElement("div", { className: classes.array }, React.createElement(Chip, { key: item, label: preview, onDelete: e => this.handleDelete(e, item), className: classes.chipDrag, deleteIcon: React.createElement(CancelIcon, { className: classes.icon }), disabled: disabled })); }), (multiple || this.state.files.length <= 0) && React.createElement("div", { className: classes.clickToUpload }, React.createElement("div", { className: classes.add }, "+"), React.createElement("div", { className: classes.uploadText }, label), React.createElement("div", { className: classes.media // style={{ backgroundImage: 'url(' + this.state.previewImg + ')' }} }))))); } if (type === 'drag') { drag = React.createElement("div", null, React.createElement(TargetBox, { accepts: [FILE], onDrop: this.handleFileDrop, beforeDragMention: this.props.beforeDragMention, onDragMention: this.props.onDragMention }, React.createElement("input", { accept: this.props.acceptType, ref: input => this.selectInput = input, className: classes.input, id: id, onChange: this.handleChangePath, type: "file", multiple: multiple, disabled: disabled }), React.createElement("label", { htmlFor: id }, React.createElement("div", { className: classes.dragToUpload }, React.createElement("div", { className: classes.array }, files.map(item => { /* 如果是图片就预览,否则显示文件名 */ const preview = React.createElement("div", { className: classes.mediaDrag // style={{ backgroundImage: 'url(' + content + ')' }} }, item.preview || item.name); return React.createElement(Chip, { key: item, label: preview, onDelete: e => this.handleDelete(e, item), className: classes.chipDrag, deleteIcon: React.createElement(CancelIcon, { className: classes.icon }), disabled: disabled }); })))))); } switch (type) { case 'manual': return manual; case 'basic': return basic; case 'img': return img; case 'drag': return drag; default: return _ref; } } } process.env.NODE_ENV !== "production" ? Upload.propTypes = { /** * 接受上传的文件类型 */ acceptType: PropTypes.string, /** * 可选参数, 拖拽上传前的文字提示 */ beforeDragMention: PropTypes.string, /** * 可选参数, 是否禁用 */ disabled: PropTypes.bool, /** * 可选参数, 组件包含的所有文件 */ files: PropTypes.array, /** * 按钮描述文字 */ label: PropTypes.string, /** * 可选参数, 是否允许同时上传多个文件 */ multiple: PropTypes.bool, /** * 上传文件集改变时触发的回调函数 */ onChange: PropTypes.func, /** * 点击删除某个文件时触发的回调函数 */ onDelete: PropTypes.func, /** * 可选参数, 拖拽文件至可拖拽区域上方时的文字提示 */ onDragMention: PropTypes.string, /** * 上传方式, 'manual', 'basic', 'img', 'drag'可选 */ type: PropTypes.oneOf(['manual', 'basic', 'img', 'drag']).isRequired, /** * 点击上传触发的函数 */ upload: PropTypes.func } : void 0; Upload.defaultProps = { acceptType: '*/*', multiple: true, disabled: false, beforeDragMention: '', onDragMention: '', files: [], onChange: files => {}, onDelete: file => {}, upload: files => {}, label: 'upload' }; export default withStyles(styles, { name: 'RMUpload' })(DragDropContext(HTML5Backend)(Upload));