UNPKG

taro-material

Version:

Mini Program components that implement Google's Material Design.

137 lines (123 loc) 3.74 kB
import Nerv from "nervjs"; import Taro from "@tarojs/taro-h5"; import PropTypes from 'prop-types'; import classNames from 'classnames'; import { View, Text } from '@tarojs/components'; import AtComponent from "../../common/component"; import { delayQuerySelector, initTestEnv } from "../../common/utils"; initTestEnv(); // 文档 export default class AtAccordion extends AtComponent { constructor() { super(...arguments); this.isCompleted = true; this.startOpen = false; this.state = { wrapperHeight: '' }; } handleClick = event => { const { open } = this.props; if (!this.isCompleted) return; this.props.onClick(!open, event); }; toggleWithAnimation() { const { open, isAnimation } = this.props; if (!this.isCompleted || !isAnimation) return; this.isCompleted = false; delayQuerySelector(this, '.at-accordion__body', 0).then(rect => { const height = parseInt(rect[0].height); const startHeight = open ? height : 0; const endHeight = open ? 0 : height; this.startOpen = false; this.setState({ wrapperHeight: startHeight }, () => { setTimeout(() => { this.setState({ wrapperHeight: endHeight }, () => { setTimeout(() => { this.isCompleted = true; this.setState({}); }, 700); }); }, 100); }); }); } componentWillReceiveProps(nextProps) { if (nextProps.open !== this.props.open) { this.startOpen = nextProps.open && nextProps.isAnimation; this.toggleWithAnimation(); } } render() { const { customStyle, className, title, icon, hasBorder, open } = this.props; const { wrapperHeight } = this.state; const rootCls = classNames('at-accordion', className); const iconCls = classNames({ 'at-icon': true, [`at-icon-${icon && icon.value}`]: icon && icon.value, 'at-accordion__icon': true }); const headerCls = classNames('at-accordion__header', { 'at-accordion__header--noborder': !hasBorder }); const arrowCls = classNames('at-accordion__arrow', { 'at-accordion__arrow--folded': !!open }); const contentCls = classNames('at-accordion__content', { 'at-accordion__content--inactive': !open && this.isCompleted || this.startOpen }); const iconStyle = { color: icon && icon.color || '', fontSize: icon && `${icon.size}px` || '' }; const contentStyle = { height: `${wrapperHeight}px` }; if (this.isCompleted) { contentStyle.height = ''; } return <View className={rootCls} style={customStyle}> <View className={headerCls} onClick={this.handleClick}> {icon && icon.value && <Text className={iconCls} style={iconStyle}></Text>} <View className="at-accordion__title">{title}</View> <View className={arrowCls}> <Text className="at-icon at-icon-chevron-down"></Text> </View> </View> <View style={contentStyle} className={contentCls}> <View className="at-accordion__body"> {this.props.children} </View> </View> </View>; } } AtAccordion.defaultProps = { open: false, customStyle: '', className: '', title: '', icon: {}, hasBorder: true, isAnimation: true, onClick: () => {} }; AtAccordion.propTypes = { customStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), className: PropTypes.oneOfType([PropTypes.array, PropTypes.string]), open: PropTypes.bool, isAnimation: PropTypes.bool, title: PropTypes.string, icon: PropTypes.object, hasBorder: PropTypes.bool, onClick: PropTypes.func };