UNPKG

taro-material

Version:

Mini Program components that implement Google's Material Design.

200 lines (173 loc) 6.4 kB
import Nerv from "nervjs"; import Taro from "@tarojs/taro-h5"; import PropTypes from 'prop-types'; import { View, ScrollView } from '@tarojs/components'; import classNames from 'classnames'; import AtComponent from "../common/component"; import AtToast from "../components/toast/index"; import { delayQuerySelector, uuid, initTestEnv, isTest } from "../common/utils"; import RMList from "../List/index"; import RMListItem from "../ListItem/index"; initTestEnv(); const ENV = Taro.getEnv(); class RMIndexes extends AtComponent { constructor() { super(...arguments); this.state = { _scrollIntoView: '', _scrollTop: 0, _tipText: '', _isShowToast: false }; // 右侧导航高度 this.menuHeight = 0; // 右侧导航距离顶部高度 this.startTop = 0; // 右侧导航元素高度 this.itemHeight = 0; // 当前索引 this.currentIndex = -1; this.listId = isTest() ? 'indexes-list-AOTU2018' : `list-${uuid()}`; } handleClick = (...arg) => this.props.onClick(...arg); handleTouchMove = event => { event.stopPropagation(); event.preventDefault(); const { list } = this.props; const pageY = event.touches[0].pageY; const index = Math.floor((pageY - this.startTop) / this.itemHeight); if (index >= 0 && index <= list.length && this.currentIndex !== index) { this.currentIndex = index; const key = index > 0 ? list[index - 1].key : 'top'; const touchView = `at-indexes__list-${key}`; this.jumpTarget(touchView, index); } }; handleTouchEnd = () => { this.currentIndex = -1; }; jumpTarget(_scrollIntoView, idx) { const { topKey, list } = this.props; const _tipText = idx === 0 ? topKey : list[idx - 1].key; if (ENV === Taro.ENV_TYPE.WEB) { delayQuerySelector(this, '.at-indexes', 0).then(rect => { const targetOffsetTop = this.listRef.childNodes[idx].offsetTop; const _scrollTop = targetOffsetTop - rect[0].top; this.updateState({ _scrollTop, _scrollIntoView, _tipText }); }); return; } this.updateState({ _scrollIntoView, _tipText }); } updateState(state) { const { isShowToast, isVibrate } = this.props; const { _scrollIntoView, _tipText, _scrollTop } = state; this.setState({ _scrollIntoView, _tipText, _scrollTop, _isShowToast: isShowToast }); if (isVibrate) { Taro.vibrateShort(); } } initData() { delayQuerySelector(this, '.at-indexes__menu').then(rect => { const len = this.props.list.length; this.menuHeight = rect[0].height; this.startTop = rect[0].top; this.itemHeight = Math.floor(this.menuHeight / (len + 1)); }); } componentWillReceiveProps(nextProps) { if (nextProps.list.length !== this.props.list.length) { this.initData(); } } componentDidMount() { if (ENV === Taro.ENV_TYPE.WEB) { this.listRef = document.getElementById(this.listId); } this.initData(); } render() { const { className, customStyle, animation, topKey, list, ListProps, ListItemProps } = this.props; const { _scrollTop, _scrollIntoView, _tipText, _isShowToast } = this.state; const toastStyle = { minWidth: Taro.pxTransform(100) }; const rootCls = classNames('at-indexes', className); const menuList = list.map((dataList, i) => { const { key } = dataList; const targetView = `at-indexes__list-${key}`; return <View className="at-indexes__menu-item" key={key} onClick={this.jumpTarget.bind(this, targetView, i + 1)}> {key} </View>; }); const indexesList = list.map(dataList => <View id={`at-indexes__list-${dataList.key}`} className="at-indexes__list" key={dataList.key}> <View className="at-indexes__list-title">{dataList.title}</View> <RMList hasBorder={ListProps.hasBorder} customStyle={ListProps.customStyle}> {dataList.items && dataList.items.map((item, i) => <RMListItem key={item.id || item.title || item.name} title={item.title || item.name} onClick={this.handleClick.bind(this, item)} note={item.note} thumb={item.thumb} iconThumb={item.iconThumb} iconThumbFill={item.iconThumbFill} iconThumbColor={item.iconThumbColor} isSwitch={item.isSwitch} switchIsCheck={item.switchIsCheck} extraText={item.extraText} extraTextColor={item.extraTextColor} extraThumb={item.extraThumb} extraIconThumb={item.extraIconThumb} extraIconThumbFill={item.extraIconThumbFill} extraIconThumbColor={item.extraIconThumbColor} arrow={item.arrow} disabled={item.disabled} badge={item.badge} hasBorder={ListItemProps.hasBorder} customStyle={ListItemProps.customStyle} />)} </RMList> </View>); return <View className={rootCls} style={customStyle}> <AtToast customStyle={toastStyle} isOpened={_isShowToast} text={_tipText} duration={2000} /> <View className="at-indexes__menu" onTouchMove={this.handleTouchMove} onTouchEnd={this.handleTouchEnd}> <View className="at-indexes__menu-item" onClick={this.jumpTarget.bind(this, 'at-indexes__top', 0)}> {topKey} </View> {menuList} </View> <ScrollView className="at-indexes__body" id={this.listId} scrollY scrollWithAnimation={animation} scrollTop={_scrollTop} scrollIntoView={_scrollIntoView}> <View className="at-indexes__content" id="at-indexes__top"> {this.props.children} </View> {indexesList} </ScrollView> </View>; } } RMIndexes.propTypes = { customStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), className: PropTypes.oneOfType([PropTypes.array, PropTypes.string]), animation: PropTypes.bool, isVibrate: PropTypes.bool, isShowToast: PropTypes.bool, topKey: PropTypes.string, list: PropTypes.array, onClick: PropTypes.func, ListProps: PropTypes.shape({ hasBorder: PropTypes.bool }), ListItemProps: PropTypes.shape({ hasBorder: PropTypes.bool }) }; RMIndexes.defaultProps = { isTest: false, customStyle: '', className: '', animation: false, topKey: 'Top', isVibrate: true, isShowToast: true, list: [], onClick: () => {}, ListProps: { hasBorder: false }, ListItemProps: { hasBorder: true } }; export default RMIndexes;