taro-material
Version:
Mini Program components that implement Google's Material Design.
361 lines (315 loc) • 8.4 kB
JavaScript
import Taro, { Component } from '@tarojs/taro';
import PropTypes from 'prop-types';
import { View, Image, Label } from '@tarojs/components';
import classNames from 'classnames';
import RMIcon from '../Icon';
import RMTypography from '../Typography';
import theme from '../styles/theme';
import './Upload.scss';
function uploadFile(url, item, params, resolve, reject) {
if (RMUpload.queue > 10) {
return setTimeout(() => {
uploadFile(url, item, params, resolve, reject);
}, 300);
}
Taro.uploadFile({
url,
filePath: item,
name: 'file',
formData: params,
fail(res) {
reject(res);
},
complete(res) {
if ((res.statusCode >= 200 && res.statusCode < 300) || res.statusCode === 304) {
// 去掉微信返回的url多出的引号
const data = res.data.slice(1, -1);
resolve(data);
} else {
reject(res);
}
RMUpload.queue--;
},
});
}
class RMUpload extends Component {
static queue = 0;
constructor(props) {
super(props);
this.state = {
_files: [],
};
this._files = [];
}
componentWillReceiveProps(nextProps) {
const { files } = this.props;
let isEqual =
files.length === nextProps.files.length &&
files.every((item, i) => item === nextProps.files[i]);
if (!isEqual) {
this.reset();
this.init(nextProps.files);
}
}
componentDidMount() {
// this.init()
this.reset();
this.init(this.props.files);
const { onComponentDidMount } = this.props;
onComponentDidMount && onComponentDidMount(this);
}
componentDidUpdate(prevProps, prevState) {
const { onChange, disabled } = this.props;
if (!disabled && prevState._files !== this.state._files) {
onChange(this.state._files);
}
}
init(files) {
const _files = files || this.props.files;
for (let i = 0; i < _files.length; i++) {
this.pathHandler(_files[i]);
}
}
reset = () => {
const { _files } = this.state;
for (let i = _files.length - 1; i >= 0; i--) {
const file = _files[i];
this.handleDelete(file);
}
RMUpload.queue = 0;
};
pathHandler(file) {
if (!file) {
return;
}
const __files = this._files;
if (__files.indexOf(file) > -1) {
return;
}
const { multiple } = this.props;
let { maxLength } = this.props;
if (multiple) {
if (!maxLength) {
maxLength = 2;
}
} else {
maxLength = 1;
}
if (!multiple) {
const { _files } = this.state;
if (_files.length > 0) {
for (let i = 0; i < _files.length; i++) {
this.handleDelete(null, _files[i]);
}
}
}
const { length } = __files;
if (length >= maxLength) {
Taro.showModal({
title: '提示',
content: `最多只允许传递${maxLength}个文件!`,
showCancel: false,
confirmText: 'OK',
confirmColor: theme.palette.primary.main,
success(res) {},
});
return;
}
this.setState(preState => ({
_files: multiple ? [...preState._files, file] : [file],
}));
this._files = multiple ? [...this._files, file] : [file];
}
handleDelete = (item, e) => {
const { disabled } = this.props;
if (disabled) {
return;
}
const { _files } = this.state;
let indexToDelete = _files.indexOf(item);
if (indexToDelete !== -1) {
_files.splice(indexToDelete, 1);
}
indexToDelete = this._files.indexOf(item);
if (indexToDelete !== -1) {
this._files.splice(indexToDelete, 1);
}
this.setState({
_files: _files.slice(),
});
if (this.props.onDelete) {
this.props.onDelete(item);
}
e && e.stopPropagation();
};
/* 通过点击Input标签添加图片 */
chooseImage = e => {
const { disabled } = this.props;
if (disabled) {
return;
}
const { multiple } = this.props;
const { length } = this._files;
let { maxLength } = this.props;
if (multiple) {
if (!maxLength) {
maxLength = 2;
}
} else {
maxLength = 1;
}
const count = maxLength - length;
Taro.chooseImage({
count,
success: res => {
const tempFilePaths = res.tempFilePaths;
for (let i = 0; i < tempFilePaths.length; i++) {
const file = tempFilePaths[i];
this.pathHandler(file);
}
},
fail() {},
});
};
upload = (url, params) => {
const { disabled, files } = this.props;
const { _files } = this.state;
if (disabled || !url || !_files || _files.length <= 0) {
return Promise.resolve([]);
}
return Promise.all(
_files.map(
item =>
new Promise((resolve, reject) => {
if (files.indexOf(item) !== -1) {
// /^http(s?):\/\//g.test(item)
return resolve(item);
}
RMUpload.queue++;
uploadFile(url, item, params, resolve, reject);
}),
),
);
};
preview = item => {
Taro.previewImage({
current: item, // 当前显示图片的http链接
urls: [item], // 需要预览的图片http链接列表
success() {},
fail() {},
});
};
render() {
const {
multiple,
disabled,
label,
placeholder,
required,
helperText,
helperTextStyle,
helperTextClass,
square,
} = this.props;
const { _files } = this.state;
const { length } = _files;
let { maxLength } = this.props;
if (multiple) {
if (!maxLength) {
maxLength = 2;
}
} else {
maxLength = 1;
}
return (
<View
className={classNames({
'rm-upload': true,
rounded: !square,
})}
>
{label && (
<Label className="title">
<RMTypography className="subheading" color="inherit" block>
{label}
</RMTypography>
<View className="required">
<RMTypography className="subheading" color="inherit">
{required ? '*' : ''}
</RMTypography>
</View>
</Label>
)}
<View className="files" disabled={disabled}>
{_files.map(item => {
const url = `${item}`;
return (
<View key={url} className="chip" onClick={this.preview.bind(this, url)}>
<View className="media" style={{ backgroundImage: `url(${url})` }}>
<Image className="media" src={url} />
<View className="close" onClick={this.handleDelete.bind(this, url)}>
<RMIcon fontSize={16} color="default" block>
close
</RMIcon>
</View>
</View>
</View>
);
})}
{(multiple || length <= 0) && length < maxLength && (
<View className="clickToUpload" onClick={this.chooseImage}>
<View className="add">
<RMIcon fontSize={28} color="default" block>
add
</RMIcon>
</View>
<View className="uploadText">{placeholder}</View>
</View>
)}
</View>
<View
className={classNames({
'helper-text': true,
[helperTextClass]: !!helperTextClass,
})}
style={helperTextStyle}
>
{helperText && (
<View className="helper-text-icon">
<RMIcon color="inherit" fontSize="default" block>
warning
</RMIcon>
</View>
)}
<RMTypography color="inherit" className="caption" block>
{helperText || ''}
</RMTypography>
</View>
</View>
);
}
}
RMUpload.defaultProps = {
acceptType: '*/*',
multiple: true,
disabled: false,
files: [],
label: 'upload',
name: '',
maxLength: 9,
required: false,
placeholder: '',
helperText: '',
helperTextStyle: '',
helperTextClass: '',
square: false,
onChange: () => {},
onDelete: () => {},
onComponentDidMount: () => {},
};
RMUpload.propTypes = {
multiple: PropTypes.bool,
disabled: PropTypes.bool,
maxLength: PropTypes.number,
};
export default RMUpload;