src/scrollview/Bar.js
/**
* @file melon/ScrollViewBar
* @author cxtom<[email protected]>
*/
import React, {Component, PropTypes} from 'react';
import {create} from 'melon-core/classname/cxBuilder';
import * as dom from '../common/util/dom';
import {throttle} from '../common/util/fn';
const cx = create('ScrollviewBar');
export default class ScrollViewBar extends Component {
constructor(props) {
super(props);
this.removeStateShow = throttle(this.removeStateShow.bind(this), 100);
this.onBarMouseDown = this.onBarMouseDown.bind(this);
this.onMouseDown = this.onMouseDown.bind(this);
this.onMouseUp = this.onMouseUp.bind(this);
this.onMouseMove = this.onMouseMove.bind(this);
this.state = {};
}
componentDidMount() {
this.positionThumb();
}
shouldComponentUpdate(nextProps) {
if (Math.abs(nextProps.position - this.props.position) < 0.0005) {
return false;
}
dom.addClass(this.refs.main, 'state-show');
this.removeStateShow();
return true;
}
componentDidUpdate() {
this.positionThumb();
}
componentWillUnmount() {
this.clearTimer();
}
positionThumb() {
let {
main,
thumb
} = this.refs;
let {
direction,
position,
thumbSize
} = this.props;
let isVertical = direction === 'vertical';
let axis = isVertical ? 'top' : 'left';
this.barSize = main[isVertical ? 'offsetHeight' : 'offsetWidth'] - thumbSize - 4;
thumb.style[isVertical ? 'height' : 'width'] = thumbSize + 'px';
thumb.style[axis] = Math.round(position * this.barSize) + 'px';
}
getMousePosition(e, isVertical) {
if (isVertical) {
return e.pageY || e.clientY;
}
return e.pageX || e.clientX;
}
clearTimer() {
if (this.timer) {
clearTimeout(this.timer);
}
}
removeStateShow() {
this.clearTimer();
let main = this.refs.main;
this.timer = setTimeout(function () {
dom.removeClass(main, 'state-show');
}, 1800);
}
/**
* 点击滚动轨道触发
*
* @param {Object} e MouseEvent
*/
onBarMouseDown(e) {
let target = e.target;
if (target === this.refs.thumb) {
return;
}
let {
direction,
thumbSize
} = this.props;
let {
main
} = this.refs;
let me = this;
let isVertical = direction === 'vertical';
let axis = isVertical ? 'top' : 'left';
let barSize = main[isVertical ? 'offsetHeight' : 'offsetWidth'] - thumbSize - 4;
let mousePos = this.getMousePosition(e, isVertical) - dom.getPosition(main)[axis];
let pos = mousePos - thumbSize / 2;
pos = pos > barSize ? barSize : pos;
pos = pos < 0 ? 0 : pos;
me.fireAction('change', pos / barSize);
e.preventDefault();
}
onMouseDown(e) {
let body = document.body;
dom.addClass(body, 'ui-noselect');
let isVertical = this.props.direction === 'vertical';
let axis = isVertical ? 'top' : 'left';
this.thumbStart = parseInt(this.refs.thumb.style[axis], 10) || 0;
this.moveStart = this.getMousePosition(e, isVertical);
dom.on(body, 'mousemove', this.onMouseMove);
dom.on(body, 'mouseup', this.onMouseUp);
e.preventDefault();
}
onMouseMove(e) {
e = e || window.event;
let isVertical = this.props.direction === 'vertical';
let moveLength = this.getMousePosition(e, isVertical);
moveLength -= this.moveStart;
let pos = Math.min(this.barSize, Math.max(0, this.thumbStart + moveLength));
this.fireAction('change', pos / this.barSize);
}
onMouseUp(e) {
let body = document.body;
dom.removeClass(body, 'ui-noselect');
dom.off(body, 'mousemove', this.onMouseMove);
dom.off(body, 'mouseup', this.onMouseUp);
this.thumbStart = this.moveStart = 0;
}
fireAction(action, pos) {
let e = {
action: action,
position: pos,
target: this
};
let onAction = this.props.onAction;
onAction && onAction(e);
}
render() {
return (
<div
{...this.props}
ref="main"
className={cx(this.props).addVariants(this.props.direction).build()}
onMouseDown={this.onBarMouseDown}>
<div
ref="thumb"
className={cx().part('thumb').build()}
onMouseDown={this.onMouseDown} />
</div>
);
}
}
ScrollViewBar.displayName = 'ScrollViewBar';
ScrollViewBar.propTypes = {
direction: PropTypes.oneOf(['vertical', 'horizontal']).isRequired,
position: PropTypes.number.isRequired,
thumbSize: PropTypes.number,
show: PropTypes.bool,
onAction: PropTypes.func
};