taro-material
Version:
Mini Program components that implement Google's Material Design.
300 lines (267 loc) • 9.1 kB
JavaScript
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 RMIcon from "../Icon/index";
import RMTypography from "../Typography/index";
import './index.scss';
class RMNoticeBar extends AtComponent {
// initial = false;
constructor() {
super(...arguments);
const animElemId = `J_${Date.now()}_${Math.ceil(Math.random() * 10e5).toString(36)}`;
this.state = {
show: true,
animElemId,
dura: 0.015,
isWEAPP: Taro.getEnv() === Taro.ENV_TYPE.WEAPP,
isWEB: Taro.getEnv() === Taro.ENV_TYPE.WEB
};
}
ref = node => this.animElem = node;
componentWillReceiveProps() {
// if (!this.timeout) {
// this.interval && clearInterval(this.interval)
// this.initAnimation()
// }
}
componentDidShow() {
// if (!this.initial) {
// return;
// }
// if (!this.props.marquee) {
// return;
// }
// this.initAnimation();
}
componentDidHide() {
// if (!this.initial) {
// return;
// }
// this.interval && clearInterval(this.interval);
}
componentDidMount() {
// this.initial = true;
if (!this.props.marquee) {
return;
}
this.initAnimation();
}
componentWillUnmount() {
this.interval && clearInterval(this.interval);
this.timeout && clearTimeout(this.timeout);
}
initAnimation() {
const { vertical, infinite, pauseTime, duration } = this.props;
const { rows } = this.props;
let length = 0;
if (vertical) {
length = rows * 18;
}
this.timeout = setTimeout(() => {
this.timeout && clearTimeout(this.timeout);
if (this.state.isWEB) {
// const elem = this.animElem // document.querySelector(`.${this.state.animElemId}`)
// if (elem) {
// const width = vertical
// ? elem.getBoundingClientRect().height
// : elem.getBoundingClientRect().width
// }
} else if (this.state.isWEAPP) {
const query = Taro.createSelectorQuery().in(this.$scope);
this.animElem = query.select(`#${this.state.animElemId}`);
let index = 0;
const resetAnimation = Taro.createAnimation({
duration: 0,
timingFunction: 'ease'
});
const animation = Taro.createAnimation({
duration,
timingFunction: 'ease'
});
const nodeRef = this.animElem.boundingClientRect(res => {
if (!res) return;
const { width, height } = res;
// console.log(`notice bar: width: ${width}, height: ${height}`)
if (!width || !height) {
return;
}
if (vertical) {
const y = -length * index;
const _h = -height + (infinite ? 0 : length) - 6;
if (!pauseTime || y <= _h) {
resetAnimation.translateY(height).step();
index = 0;
}
} else {
resetAnimation.translateX(0).step();
}
this.setState({ animationData: resetAnimation.export() });
setTimeout(() => {
if (vertical) {
let y = 0;
if (pauseTime) {
y = -length * index++;
const _h = -height + (infinite ? 0 : length) - 6;
if (y <= _h + length) {
setTimeout(() => {
animBody();
}, duration);
}
if (y <= _h) {
y = _h;
}
} else {
y = -height + (infinite ? 0 : length);
}
animation.translateY(y).step();
} else {
animation.translateX(-width + (infinite ? 0 : 100)).step();
}
this.setState({ animationData: animation.export() });
}, 500);
});
const animBody = () => {
nodeRef.exec();
};
animBody();
if (infinite) {
this.interval && clearInterval(this.interval);
this.interval = setInterval(animBody, duration + 500 + pauseTime);
}
}
}, 100);
}
onClose() {
this.setState({
show: false
});
this.props.onClose && this.props.onClose(...arguments);
}
onGotoMore() {
this.props.onGotoMore && this.props.onGotoMore(...arguments);
}
render() {
const {
icon,
iconColor,
customStyle,
marquee,
vertical,
color,
rows,
showMore,
close,
unread
} = this.props;
const height = rows * 18;
const { animationData, animElemId } = this.state;
const rootClassName = ['rm-noticebar'];
const _moreText = this.props.moreText;
const single = rows === 1;
// if (!single) showMore = false;
// if (!_moreText) _moreText = '查看详情'
const style = {};
const contentStyle = {};
const innerClassName = ['rm-noticebar__content-inner'];
if (marquee) {
// close = false
// style['animation-duration'] = `${dura * 1000}s`
// innerClassName.push(this.state.animElemId)
if (vertical) {
innerClassName.push('vertical');
}
}
if (height) {
contentStyle.height = `${height}px`;
}
let _color = '';
if (color && color.length >= 1) {
_color = color.charAt(0).toUpperCase() + color.substring(1);
}
const classObject = {
'rm-noticebar--marquee': marquee,
'rm-noticebar--weapp': marquee && this.state.isWEAPP,
'rm-noticebar--more': !marquee && showMore,
'rm-noticebar--single': single || marquee && !vertical, // ! marquee &&
[`color${_color}`]: color !== 'inherit'
};
return this.state.show && <View className={classNames(rootClassName, classObject, this.props.className)} style={customStyle}>
<View className="rm-noticebar__content">
{close && <View className="rm-noticebar__close" onClick={this.onClose.bind(this)}>
<RMIcon color="action" fontSize={24}>
close
</RMIcon>
</View>}
{icon && <View className="rm-noticebar__content-icon">
<RMIcon color={iconColor || 'inherit'} fontSize={24}>
{icon}
</RMIcon>
</View>}
<View className="rm-noticebar__content-text" style={contentStyle}>
<View animation={animationData} className={innerClassName} style={style}
// ref={this.ref}
id={animElemId}>
<RMTypography className="body1" color="inherit" fontSize="inherit" block>
{this.props.children}
</RMTypography>
</View>
</View>
{showMore && <View className="rm-noticebar__more" onClick={this.onGotoMore.bind(this)}>
{unread && <View className="unread" />}
<Text className="text">{_moreText}</Text>
<View className="rm-noticebar__more-icon">
<RMIcon color="inherit" fontSize={24}>
chevron_right
</RMIcon>
</View>
</View>}
</View>
</View>;
}
}
RMNoticeBar.propTypes = {
close: PropTypes.bool, // 是否需要关闭按钮 Boolean - false
marquee: PropTypes.bool, // 内容是否滚动(内容只能单行) Boolean - false
duration: PropTypes.number, // 内容滚动速度 (默认速度100px/秒) Number - 100
moreText: PropTypes.string, // “查看更多”链接文本 String - 查看详情
moreUrl: PropTypes.string, // “查看更多”链接地址 String - -
icon: PropTypes.string, // 内容前的icon图标 String 参考icon组件
customStyle: PropTypes.object,
vertical: PropTypes.bool, // 滚动方向是否为纵向
color: PropTypes.oneOf(['inherit', 'primary', 'secondary', 'action', 'error', 'disabled', 'success', 'warning', 'progress', 'default']),
iconColor: PropTypes.oneOf(['inherit', 'primary', 'secondary', 'action', 'error', 'disabled', 'success', 'warning', 'progress', 'default']),
showMore: PropTypes.bool,
onClose: PropTypes.func,
onGotoMore: PropTypes.func,
infinite: PropTypes.bool,
pauseTime: PropTypes.number,
rows: PropTypes.number, // 内容是否单行 Boolean - false
unread: PropTypes.bool
};
RMNoticeBar.defaultProps = {
close: false,
marquee: false,
moreText: '查看详情',
moreUrl: '',
showMore: false,
icon: '',
iconColor: 'inherit',
customStyle: {},
vertical: false,
/**
* enum: 'inherit', 'primary', 'secondary', 'action', 'error', 'disabled', 'success', 'warning', 'progress', 'default'
* The color of the component. It supports those theme colors that make sense for this component.
*/
color: 'default',
onClose: () => {},
onGotoMore: () => {},
infinite: true,
pauseTime: 0,
duration: 20000,
rows: 0,
unread: false
};
export default RMNoticeBar;