taro-material
Version:
Mini Program components that implement Google's Material Design.
177 lines (159 loc) • 5.24 kB
JavaScript
import Nerv from "nervjs";
import Taro from "@tarojs/taro-h5";
import PropTypes from 'prop-types';
import { View } from '@tarojs/components';
import classNames from 'classnames';
import { delayQuerySelector, getEventDetail } from "../../common/utils";
import AtComponent from "../../common/component";
export default class AtRange extends AtComponent {
constructor(props) {
super(...arguments);
const { max, min } = props;
// range 宽度
this.width = 0;
// range 到屏幕左边的距离
this.left = 0;
this.deltaValue = max - min;
this.currentSlider = '';
this.state = {
aX: 0,
bX: 0
};
}
handleClick = event => {
if (this.currentSlider && !this.props.disabled) {
let sliderValue = 0;
const detail = getEventDetail(event);
sliderValue = detail.x - this.left;
this.setSliderValue(this.currentSlider, sliderValue, 'onChange');
}
};
handleTouchMove(sliderName, event) {
if (this.props.disabled) return;
event.stopPropagation();
const clientX = event.touches[0].clientX;
this.setSliderValue(sliderName, clientX - this.left, 'onChange');
}
handleTouchEnd(sliderName) {
if (this.props.disabled) return;
this.currentSlider = sliderName;
this.triggerEvent('onAfterChange');
}
setSliderValue(sliderName, targetValue, funcName) {
const distance = Math.min(Math.max(targetValue, 0), this.width);
const sliderValue = Math.floor(distance / this.width * 100);
if (funcName) {
this.setState({
[sliderName]: sliderValue
}, () => this.triggerEvent(funcName));
} else {
this.setState({
[sliderName]: sliderValue
});
}
}
setValue(value) {
const aX = Math.round(value[0] / this.deltaValue * 100);
const bX = Math.round(value[1] / this.deltaValue * 100);
this.setState({ aX, bX });
}
triggerEvent(funcName) {
const { aX, bX } = this.state;
const a = Math.round(aX / 100 * this.deltaValue);
const b = Math.round(bX / 100 * this.deltaValue);
const result = [a, b].sort((x, y) => x - y);
if (funcName === 'onChange') {
this.props.onChange(result);
} else if (funcName === 'onAfterChange') {
this.props.onAfterChange(result);
}
}
componentWillReceiveProps(nextProps) {
const { value } = nextProps;
if (this.props.value[0] !== value[0] && this.props.value[1] !== value[1]) {
this.setValue(value);
}
}
componentDidMount() {
const { value } = this.props;
delayQuerySelector(this, '.at-range__container', 0).then(rect => {
this.width = Math.round(rect[0].width);
this.left = Math.round(rect[0].left);
this.setValue(value);
});
}
render() {
const {
className,
customStyle,
sliderStyle,
railStyle,
trackStyle,
blockSize,
disabled
} = this.props;
const rootCls = classNames('at-range', {
'at-range--disabled': disabled
}, className);
const { aX, bX } = this.state;
const sliderCommonStyle = {
width: blockSize ? `${blockSize}PX` : '',
height: blockSize ? `${blockSize}PX` : '',
marginLeft: blockSize ? `${-blockSize / 2}PX` : ''
};
const sliderAStyle = {
...sliderCommonStyle,
left: `${aX}%`
};
const sliderBStyle = {
...sliderCommonStyle,
left: `${bX}%`
};
const containerStyle = {
height: blockSize ? `${blockSize}PX` : ''
};
const smallerX = Math.min(aX, bX);
const deltaX = Math.abs(aX - bX);
const atTrackStyle = {
left: `${smallerX}%`,
width: `${deltaX}%`
};
return <View className={rootCls} style={customStyle} onClick={this.handleClick}>
<View className="at-range__container" style={containerStyle}>
<View className="at-range__rail" style={railStyle} />
<View className="at-range__track" style={this.mergeStyle(atTrackStyle, trackStyle)} />
<View className="at-range__slider" style={this.mergeStyle(sliderAStyle, sliderStyle)} onTouchMove={this.handleTouchMove.bind(this, 'aX')} onTouchEnd={this.handleTouchEnd.bind(this, 'aX')} />
<View className="at-range__slider" style={this.mergeStyle(sliderBStyle, sliderStyle)} onTouchMove={this.handleTouchMove.bind(this, 'bX')} onTouchEnd={this.handleTouchEnd.bind(this, 'bX')} />
</View>
</View>;
}
}
AtRange.defaultProps = {
customStyle: '',
className: '',
sliderStyle: '',
railStyle: '',
trackStyle: '',
value: [0, 0],
min: 0,
max: 100,
disabled: false,
blockSize: 0,
onChange: () => {},
onAfterChange: () => {}
};
AtRange.propTypes = {
customStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
className: PropTypes.oneOfType([PropTypes.array, PropTypes.string]),
sliderStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
railStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
trackStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
isTest: PropTypes.bool,
value: PropTypes.array,
min: PropTypes.number,
max: PropTypes.number,
disabled: PropTypes.bool,
blockSize: PropTypes.number,
onChange: PropTypes.func,
onAfterChange: PropTypes.func
};