taro-material
Version:
Mini Program components that implement Google's Material Design.
257 lines (221 loc) • 6.95 kB
JavaScript
import Nerv from "nervjs";
import Taro, { Component } from "@tarojs/taro-h5";
import { View, ScrollView } from '@tarojs/components';
import PropTypes from 'prop-types';
import RMTag from "../Tag/index";
import RMTypography from "../Typography/index";
import theme from "../styles/theme";
import './index.scss';
class RMFilter extends Component {
state = {
scrollTop: 0,
scrollbar: { opacity: 1, visibility: 'visible', _height: 'auto' },
valueBar: { opacity: 0, visibility: 'hidden', _height: 'auto' }
};
scrollbarRef = node => this.scrollbarRefEle = node;
valueBarRef = node => this.valueBarRefEle = node;
componentDidMount() {
const { onAddPageScroll } = this.props;
if (onAddPageScroll) {
onAddPageScroll(this.handlePageScroll.bind(this));
}
// setTimeout(() => {
this.scrollbarRefEle.boundingClientRect(rect => {
if (!rect) return;
this.setState({
top: rect.top,
scrollbar: {
...rect,
opacity: 1,
visibility: 'visible',
height: rect.height,
_height: 'auto'
}
});
}).exec();
this.valueBarRefEle.boundingClientRect(rect => {
if (!rect) return;
this.setState({
valueBar: {
...rect,
opacity: 0,
visibility: 'hidden',
height: rect.height,
_height: 'auto'
}
});
}).exec();
// }, 1000);
}
componentWillUnmount() {}
componentDidShow() {}
componentDidHide() {}
handlePageScroll(params) {
const { scrollTop } = params;
const { scrollbar, valueBar, top } = this.state;
const { offsetTop } = this.props;
let comps = {};
if (scrollTop < top - offsetTop || scrollTop - offsetTop < scrollbar.height - valueBar.height) {
comps = {
scrollbar: {
...scrollbar,
opacity: 1,
visibility: 'visible',
_height: scrollbar.height
},
valueBar: {
...valueBar,
opacity: 0,
visibility: 'hidden',
_height: 0
}
};
} else if (scrollTop - offsetTop < scrollbar.height) {
const h = scrollTop - offsetTop - scrollbar.height + valueBar.height;
const opacity = h / valueBar.height;
comps = {
scrollbar: {
...scrollbar,
opacity: 1 - opacity,
visibility: 'visible',
_height: scrollbar.height - h
},
valueBar: {
...valueBar,
opacity,
visibility: 'visible',
_height: h
}
};
} else if (scrollTop - offsetTop >= scrollbar.height) {
comps = {
scrollbar: {
...scrollbar,
opacity: 0,
visibility: 'hidden',
_height: scrollbar.height - valueBar.height
},
valueBar: {
...valueBar,
opacity: 1,
visibility: 'visible',
_height: valueBar.height
}
};
}
let other = {};
if (scrollTop >= 0) {
other = {
scrollTop
};
}
this.setState({
...comps,
...other
});
}
handleClick(name, option, e) {
const { values, onChange } = this.props;
const { value, disabled } = option;
if (disabled) {
return;
}
onChange && onChange({
...values,
[name]: value
}, e);
}
handleReset(name, e) {
const { values, onChange } = this.props;
const rs = {
...values
};
delete rs[name];
onChange && onChange(rs, e);
}
getValuesText() {
const { values, data } = this.props;
const text = [];
Object.keys(values).forEach(key => {
const d = data.find(item => item.name === key);
if (d) {
const op = d.options.find(option => option.value === values[key]);
if (op) {
text.push(op.label);
}
}
});
return text.join(' · ') || '暂无过滤条件';
}
render() {
const { data, values, offsetTop, color, selectedColor, customStyle } = this.props;
const { scrollbar, valueBar } = this.state;
const valuesText = this.getValuesText();
let _color = theme.palette[selectedColor];
const valColor = _color ? _color.main : theme.palette.text.primary;
_color = theme.palette[color];
const labelColor = _color ? _color.contrastText : color;
return <View className="tagbar">
<View ref={this.scrollbarRef} style={{
...customStyle,
opacity: scrollbar.opacity,
// height: `${scrollbar._height}px`,
visibility: scrollbar.visibility
}}>
{data.map((item, index) => <ScrollView key={item.name} scrollX scrollWithAnimation style={{ width: 'auto' }}>
<View className="scrollbar">
<View onClick={this.handleReset.bind(this, item.name)} className="tag">
{!values[item.name] ? <RMTag circle color={selectedColor} size="small" active block>
{item.label}
</RMTag> : <RMTypography color={labelColor} className="body1" block>
{item.label}
</RMTypography>}
</View>
{item.options.map((option, key) => {
const active = !option.disabled && values[item.name] === option.value;
return <View onClick={this.handleClick.bind(this, item.name, option)} className="tag" key={option.value}>
{active ? <RMTag circle color={selectedColor} size="small" active block>
{option.label}
</RMTag> : <RMTypography color={labelColor} className="body1" block>
{option.label}
</RMTypography>}
</View>;
})}
</View>
</ScrollView>)}
</View>
<View className="vals" ref={this.valueBarRef} style={{
...customStyle,
opacity: valueBar.opacity,
height: `${valueBar._height}px`,
visibility: valueBar.visibility,
top: `${offsetTop}px`
}}>
<RMTypography color={valColor} className="body2" block>
{valuesText}
</RMTypography>
</View>
</View>;
}
}
RMFilter.propTypes = {
onChange: PropTypes.func,
onAddPageScroll: PropTypes.func,
data: PropTypes.array,
values: PropTypes.object,
offsetTop: PropTypes.number,
customStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
selectedColor: PropTypes.oneOf(['default', 'primary', 'secondary', 'error', 'success', 'warning', 'progress']),
color: PropTypes.oneOf(['default', 'inherit', 'primary', 'secondary', 'error', 'success', 'warning', 'progress'])
};
RMFilter.defaultProps = {
onChange: () => {},
data: [],
values: {},
onAddPageScroll: () => {},
offsetTop: 0,
color: 'default',
selectedColor: 'primary',
customStyle: {}
};
export default RMFilter;