taro-material
Version:
Mini Program components that implement Google's Material Design.
136 lines (128 loc) • 4.53 kB
JavaScript
import Nerv from "nervjs";
/* eslint-disable no-nested-ternary */
import Taro from "@tarojs/taro-h5";
import { View, Image } from '@tarojs/components';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import AtComponent from "../../common/component";
import { uuid } from "../../common/utils";
// 生成 jsx 二维矩阵
const generateMatrix = (files, col, showAddBtn) => {
const matrix = [];
const length = showAddBtn ? files.length + 1 : files.length;
const row = Math.ceil(length / col);
for (let i = 0; i < row; i++) {
if (i === row - 1) {
// 最后一行数据加上添加按钮
const lastArr = files.slice(i * col);
if (lastArr.length < col) {
if (showAddBtn) {
lastArr.push({ type: 'btn', uuid: uuid() });
}
// 填补剩下的空列
for (let j = lastArr.length; j < col; j++) {
lastArr.push({ type: 'blank', uuid: uuid() });
}
}
matrix.push(lastArr);
} else {
matrix.push(files.slice(i * col, (i + 1) * col));
}
}
return matrix;
};
const ENV = Taro.getEnv();
export default class AtImagePicker extends AtComponent {
chooseFile = () => {
const { files = [], multiple, count, sizeType, sourceType } = this.props;
const filePathName = ENV === Taro.ENV_TYPE.ALIPAY ? 'apFilePaths' : 'tempFiles';
// const count = multiple ? 99 : 1
const params = {};
if (multiple) {
params.count = 99;
}
if (count) {
params.count = count;
}
if (sizeType) {
params.sizeType = sizeType;
}
if (sourceType) {
params.sourceType = sourceType;
}
Taro.chooseImage(params).then(res => {
const targetFiles = res.tempFilePaths.map((path, i) => ({
url: path,
file: res[filePathName][i]
}));
const newFiles = files.concat(targetFiles);
this.props.onChange(newFiles, 'add');
}).catch(this.props.onFail);
};
handleImageClick = idx => this.props.onImageClick(idx, this.props.files[idx]);
handleRemoveImg = idx => {
const { files = [] } = this.props;
if (ENV === Taro.ENV_TYPE.WEB) {
window.URL.revokeObjectURL(files[idx].url);
}
const newFiles = files.filter((file, i) => i !== idx);
this.props.onChange(newFiles, 'remove', idx);
};
render() {
const {
className,
customStyle,
files,
mode,
length,
showAddBtn
} = this.props;
// 行数
const matrix = generateMatrix(files, length, showAddBtn);
const rootCls = classNames('at-image-picker', className);
return <View className={rootCls} style={customStyle}>
{matrix.map((row, i) => <View className="at-image-picker__flex-box" key={i}>
{row.map((item, j) => item.url ? <View className="at-image-picker__flex-item" key={i * length + j}>
<View className="at-image-picker__item">
<View className="at-image-picker__remove-btn" onClick={this.handleRemoveImg.bind(this, i * length + j)}></View>
<Image className="at-image-picker__preview-img" mode={mode} src={item.url} onClick={this.handleImageClick.bind(this, i * length + j)} />
</View>
</View> : <View className="at-image-picker__flex-item" key={i * length + j}>
{item.type === 'btn' && <View className="at-image-picker__item at-image-picker__choose-btn" onClick={this.chooseFile}>
<View className="add-bar"></View>
<View className="add-bar"></View>
</View>}
</View>)}
</View>)}
</View>;
}
}
AtImagePicker.defaultProps = {
isTest: false,
className: '',
customStyle: '',
files: [],
mode: 'aspectFill',
showAddBtn: true,
multiple: false,
length: 4,
onChange: () => {},
onImageClick: () => {},
onFail: () => {}
};
AtImagePicker.propTypes = {
className: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
customStyle: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
isTest: PropTypes.bool,
files: PropTypes.array,
mode: PropTypes.oneOf(['scaleToFill', 'aspectFit', 'aspectFill', 'widthFix', 'top', 'bottom', 'center', 'left', 'right', 'top left', 'top right', 'bottom left', 'bottom right']),
showAddBtn: PropTypes.bool,
multiple: PropTypes.bool,
length: PropTypes.number,
onChange: PropTypes.func,
onImageClick: PropTypes.func,
onFail: PropTypes.func,
count: PropTypes.number,
sizeType: PropTypes.array,
sourceType: PropTypes.array
};