taro-material
Version:
Mini Program components that implement Google's Material Design.
169 lines (160 loc) • 4.86 kB
JavaScript
/* eslint-disable no-nested-ternary */
import Taro from '@tarojs/taro'
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,
}