From 33e2ee6e9a0f889579af14cfab024156e2d8803d Mon Sep 17 00:00:00 2001 From: Benjy Cui Date: Thu, 15 Oct 2015 16:31:48 +0800 Subject: [PATCH 1/4] refactor Slider with ES6 --- src/Slider.jsx | 188 +++++++++++++++++++++++-------------------------- 1 file changed, 89 insertions(+), 99 deletions(-) diff --git a/src/Slider.jsx b/src/Slider.jsx index f093049..5b8837c 100644 --- a/src/Slider.jsx +++ b/src/Slider.jsx @@ -20,76 +20,36 @@ function pauseEvent(e) { } function getValueFromIndex(props) { - let value; const marksLen = props.marks.length; - let index; - if ('index' in props) { - index = props.index; - } else { - index = props.defaultIndex; - } + const index = ('index' in props ? props.index : props.defaultIndex); + + let value; if (marksLen > 0) { value = ((props.max - props.min) / (marksLen - 1)) * (index); - value = value.toFixed(5) / 1; + value = value.toFixed(5); } return value; } -const Slider = React.createClass({ - propTypes: { - min: React.PropTypes.number, - max: React.PropTypes.number, - step: React.PropTypes.number, - defaultValue: React.PropTypes.number, - defaultIndex: React.PropTypes.number, - value: React.PropTypes.number, - index: React.PropTypes.number, - marks: React.PropTypes.array, - isIncluded: React.PropTypes.bool, - className: React.PropTypes.string, - prefixCls: React.PropTypes.string, - disabled: React.PropTypes.bool, - children: React.PropTypes.any, - onBeforeChange: React.PropTypes.func, - onChange: React.PropTypes.func, - onAfterChange: React.PropTypes.func, - tipTransitionName: React.PropTypes.string, - withDots: React.PropTypes.bool, - }, +class Slider extends React.Component { + constructor(props) { + super(props); - getDefaultProps() { - return { - min: 0, - max: 100, - step: 1, - defaultValue: 0, - marks: [], - isIncluded: true, - className: '', - prefixCls: 'rc-slider', - disabled: false, - defaultIndex: 0, - tipTransitionName: '', - withDots: false, - }; - }, - - getInitialState() { - const props = this.props; - let value = props.defaultValue; - if ('value' in props) { - value = props.value; - } + // Note: Maybe `value` is `0`, `false` and so on. + // So, check the existence of `value` with `in`. + let value = ('value' in props ? props.value : props.defaultValue); value = this._trimAlignValue(value); + const marksLen = props.marks.length; if (marksLen > 0) { value = getValueFromIndex(props); } - return { + + this.state = { dragging: false, value: value, }; - }, + } componentWillReceiveProps(nextProps) { if ('value' in nextProps) { @@ -101,20 +61,12 @@ const Slider = React.createClass({ value: getValueFromIndex(nextProps), }); } - }, - - onMouseUp() { - this._end('mouse'); - }, - - onTouchUp() { - this._end('touch'); - }, + } onMouseMove(e) { const position = e.pageX || (e.clientX + document.documentElement.scrollLeft); // to compat ie8 this.onMove(e, position); - }, + } onTouchMove(e) { if (e.touches.length > 1 || (e.type === 'touchend' && e.touches.length > 0)) { @@ -125,7 +77,7 @@ const Slider = React.createClass({ const position = this._getTouchPosition(e); this.onMove(e, position); - }, + } onMove(e, position) { pauseEvent(e); @@ -146,7 +98,7 @@ const Slider = React.createClass({ if (value !== oldValue) { this._triggerEvents('onChange', value); } - }, + } onTouchStart(e) { if (e.touches.length > 1 || (e.type.toLowerCase() === 'touchend' && e.touches.length > 0)) { @@ -159,7 +111,7 @@ const Slider = React.createClass({ this._start(position, value); this._addDocumentEvents('touch'); pauseEvent(e); - }, + } onSliderMouseDown(e) { const position = e.pageX || (e.clientX + document.documentElement.scrollLeft); // to compat ie8 @@ -168,7 +120,7 @@ const Slider = React.createClass({ this._start(position, value); this._addDocumentEvents('mouse'); pauseEvent(e); - }, + } getIndex(v) { const props = this.props; @@ -179,7 +131,7 @@ const Slider = React.createClass({ } const unit = ((props.max - props.min) / (props.marks.length - 1)).toFixed(5); return Math.round(value / unit); - }, + } getSliderLength() { const slider = this.refs.slider; @@ -188,14 +140,14 @@ const Slider = React.createClass({ } return slider.clientWidth; - }, + } getSliderStart() { const slider = this.refs.slider; const rect = slider.getBoundingClientRect(); return rect.left; - }, + } render() { const state = this.state; @@ -238,8 +190,8 @@ const Slider = React.createClass({ return (
+ onTouchStart={disabled ? noop : this.onTouchStart.bind(this)} + onMouseDown={disabled ? noop : this.onSliderMouseDown.bind(this)}> {track} ); - }, + } _trimAlignValue(v, propsArg) { let val = v; const props = propsArg || this.props; - const step = props.marks.length > 0 ? (props.max - props.min) / (props.marks.length - 1) : props.step; + const {marks, min, max} = props; + const step = marks.length > 0 ? (max - min) / (marks.length - 1) : props.step; - if (val <= props.min) { - val = props.min; + if (val <= min) { + val = min; } - if (val >= props.max) { - val = props.max; + if (val >= max) { + val = max; } - const valModStep = (val - props.min) % step; + const valModStep = (val - min) % step; let alignValue = val - valModStep; if (Math.abs(valModStep) * 2 >= step) { @@ -271,36 +224,37 @@ const Slider = React.createClass({ } return parseFloat(alignValue.toFixed(5)); - }, + } _calcOffset(value) { - const ratio = (value - this.props.min) / (this.props.max - this.props.min); + const {min, max} = this.props; + const ratio = (value - min) / (max - min); return ratio * 100; - }, + } _calcValue(offset) { + const {min, max} = this.props; const ratio = offset / this.getSliderLength(); - return ratio * (this.props.max - this.props.min) + this.props.min; - }, + return ratio * (max - min) + min; + } _calValueByPos(position) { const pixelOffset = position - this.getSliderStart(); - // pixelOffset -= (this.state.onSize / 2); const nextValue = this._trimAlignValue(this._calcValue(pixelOffset)); this.setState({ value: nextValue, }); return nextValue; - }, + } _getTouchPosition(e) { const touch = e.touches[0]; return touch.pageX; - }, + } _triggerEvents(event, v) { const props = this.props; - const hasMarks = props.marks && props.marks.length > 0; + const hasMarks = (props.marks.length > 0); if (props[event]) { let data; if (hasMarks) { @@ -312,18 +266,18 @@ const Slider = React.createClass({ } props[event](data); } - }, + } _addDocumentEvents(type) { if (type === 'touch') { // just work for chrome iOS Safari and Android Browser - this.onTouchMoveListener = DomUtils.addEventListener(document, 'touchmove', this.onTouchMove); - this.onTouchUpListener = DomUtils.addEventListener(document, 'touchend', this.onTouchUp); + this.onTouchMoveListener = DomUtils.addEventListener(document, 'touchmove', this.onTouchMove.bind(this)); + this.onTouchUpListener = DomUtils.addEventListener(document, 'touchend', this._end.bind(this, 'touch')); } else if (type === 'mouse') { - this.onMouseMoveListener = DomUtils.addEventListener(document, 'mousemove', this.onMouseMove); - this.onMouseUpListener = DomUtils.addEventListener(document, 'mouseup', this.onMouseUp); + this.onMouseMoveListener = DomUtils.addEventListener(document, 'mousemove', this.onMouseMove.bind(this)); + this.onMouseUpListener = DomUtils.addEventListener(document, 'mouseup', this._end.bind(this, 'mouse')); } - }, + } _removeEventons(type) { if (type === 'touch') { @@ -333,7 +287,7 @@ const Slider = React.createClass({ this.onMouseMoveListener.remove(); this.onMouseUpListener.remove(); } - }, + } _start(position, value) { this._triggerEvents('onBeforeChange'); @@ -342,7 +296,7 @@ const Slider = React.createClass({ this.setState({ dragging: true, }); - }, + } _end(type) { this._removeEventons(type); @@ -350,7 +304,43 @@ const Slider = React.createClass({ this.setState({ dragging: false, }); - }, -}); + } +} + +Slider.propTypes = { + min: React.PropTypes.number, + max: React.PropTypes.number, + step: React.PropTypes.number, + defaultValue: React.PropTypes.number, + defaultIndex: React.PropTypes.number, + value: React.PropTypes.number, + index: React.PropTypes.number, + marks: React.PropTypes.array, + isIncluded: React.PropTypes.bool, + className: React.PropTypes.string, + prefixCls: React.PropTypes.string, + disabled: React.PropTypes.bool, + children: React.PropTypes.any, + onBeforeChange: React.PropTypes.func, + onChange: React.PropTypes.func, + onAfterChange: React.PropTypes.func, + tipTransitionName: React.PropTypes.string, + withDots: React.PropTypes.bool, +}; + +Slider.defaultProps = { + min: 0, + max: 100, + step: 1, + defaultValue: 0, + defaultIndex: 0, + marks: [], + isIncluded: true, + className: '', + prefixCls: 'rc-slider', + disabled: false, + tipTransitionName: '', + withDots: false, +}; export default Slider; From ffbc7994554dd6ada0323b6f49857d6c044045e3 Mon Sep 17 00:00:00 2001 From: Benjy Cui Date: Tue, 20 Oct 2015 15:32:13 +0800 Subject: [PATCH 2/4] refactor: remove `prefixCls` for `Handle` --- src/Handle.jsx | 5 ++--- src/Slider.jsx | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Handle.jsx b/src/Handle.jsx index 98b968b..d355c92 100644 --- a/src/Handle.jsx +++ b/src/Handle.jsx @@ -12,7 +12,7 @@ export default class Handle extends React.Component { render() { const props = this.props; - const {className, prefixCls, offset, tipTransitionName, value} = props; + const {className, tipTransitionName, offset, value} = props; const {dragging, noTip} = props; const style = { left: offset + '%' }; @@ -27,7 +27,7 @@ export default class Handle extends React.Component { const isTooltipVisible = dragging || this.state.isTooltipVisible; return ({value}} @@ -51,7 +51,6 @@ export default class Handle extends React.Component { Handle.propTypes = { className: React.PropTypes.string, - prefixCls: React.PropTypes.string, offset: React.PropTypes.number, tipTransitionName: React.PropTypes.string, value: React.PropTypes.number, diff --git a/src/Slider.jsx b/src/Slider.jsx index 5b8837c..ca91329 100644 --- a/src/Slider.jsx +++ b/src/Slider.jsx @@ -193,9 +193,8 @@ class Slider extends React.Component { onTouchStart={disabled ? noop : this.onTouchStart.bind(this)} onMouseDown={disabled ? noop : this.onSliderMouseDown.bind(this)}> {track} - 0} /> + 0} /> {steps} {mark} {children} From 040e0fef41ac4367aa4ce93fbb5feedc64e73074 Mon Sep 17 00:00:00 2001 From: Benjy Cui Date: Tue, 20 Oct 2015 17:01:12 +0800 Subject: [PATCH 3/4] refactor: extract helper function from Slider --- src/Slider.jsx | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/Slider.jsx b/src/Slider.jsx index ca91329..1555004 100644 --- a/src/Slider.jsx +++ b/src/Slider.jsx @@ -5,7 +5,18 @@ import Handle from './Handle'; import Steps from './Steps'; import Marks from './Marks'; -function noop() { +function noop() {} + +function isNotTouchEvent(e) { + return e.touches.length > 1 || (e.type.toLowerCase() === 'touchend' && e.touches.length > 0); +} + +function getTouchPosition(e) { + return e.touches[0].pageX; +} + +function getMousePosition(e) { + return e.pageX || (e.clientX + document.documentElement.scrollLeft); // to compat ie8 } function pauseEvent(e) { @@ -64,18 +75,17 @@ class Slider extends React.Component { } onMouseMove(e) { - const position = e.pageX || (e.clientX + document.documentElement.scrollLeft); // to compat ie8 + const position = getMousePosition(e); this.onMove(e, position); } onTouchMove(e) { - if (e.touches.length > 1 || (e.type === 'touchend' && e.touches.length > 0)) { - this._end('touch'); + if (isNotTouchEvent(e)) { + this.end('touch'); return; } - const position = this._getTouchPosition(e); - + const position = getTouchPosition(e); this.onMove(e, position); } @@ -101,11 +111,9 @@ class Slider extends React.Component { } onTouchStart(e) { - if (e.touches.length > 1 || (e.type.toLowerCase() === 'touchend' && e.touches.length > 0)) { - return; - } + if (isNotTouchEvent(e)) return; - const position = this._getTouchPosition(e); + const position = getTouchPosition(e); const value = this._calValueByPos(position); this._triggerEvents('onChange', value); this._start(position, value); @@ -114,7 +122,7 @@ class Slider extends React.Component { } onSliderMouseDown(e) { - const position = e.pageX || (e.clientX + document.documentElement.scrollLeft); // to compat ie8 + const position = getMousePosition(e); const value = this._calValueByPos(position); this._triggerEvents('onChange', value); this._start(position, value); @@ -246,11 +254,6 @@ class Slider extends React.Component { return nextValue; } - _getTouchPosition(e) { - const touch = e.touches[0]; - return touch.pageX; - } - _triggerEvents(event, v) { const props = this.props; const hasMarks = (props.marks.length > 0); @@ -271,10 +274,10 @@ class Slider extends React.Component { if (type === 'touch') { // just work for chrome iOS Safari and Android Browser this.onTouchMoveListener = DomUtils.addEventListener(document, 'touchmove', this.onTouchMove.bind(this)); - this.onTouchUpListener = DomUtils.addEventListener(document, 'touchend', this._end.bind(this, 'touch')); + this.onTouchUpListener = DomUtils.addEventListener(document, 'touchend', this.end.bind(this, 'touch')); } else if (type === 'mouse') { this.onMouseMoveListener = DomUtils.addEventListener(document, 'mousemove', this.onMouseMove.bind(this)); - this.onMouseUpListener = DomUtils.addEventListener(document, 'mouseup', this._end.bind(this, 'mouse')); + this.onMouseUpListener = DomUtils.addEventListener(document, 'mouseup', this.end.bind(this, 'mouse')); } } @@ -297,7 +300,7 @@ class Slider extends React.Component { }); } - _end(type) { + end(type) { this._removeEventons(type); this._triggerEvents('onAfterChange'); this.setState({ From 3c86db909ce889cf6ceb904d178cd4283a15d5a2 Mon Sep 17 00:00:00 2001 From: Benjy Cui Date: Wed, 21 Oct 2015 14:11:55 +0800 Subject: [PATCH 4/4] feat: add support for range --- examples/simple.js | 33 +++-- src/Handle.jsx | 23 ++-- src/Slider.jsx | 312 ++++++++++++++++++++++++++------------------ src/Steps.jsx | 5 +- tests/index.spec.js | 6 +- 5 files changed, 229 insertions(+), 150 deletions(-) diff --git a/examples/simple.js b/examples/simple.js index 8893e40..5f57cca 100644 --- a/examples/simple.js +++ b/examples/simple.js @@ -4,6 +4,7 @@ require('rc-slider/assets/index.less'); var React = require('react'); var Slider = require('rc-slider'); +var style = {width:400,margin:100}; function onChange(v) { console.log(v); @@ -11,23 +12,35 @@ function onChange(v) { React.render(
-
- +
+
-
- +
+
-
- +
+
-
- +
+
-
+
+ +
+
+ +
+
+ +
+
+ +
+

包含关系

-
+

并列关系

diff --git a/src/Handle.jsx b/src/Handle.jsx index d355c92..3869059 100644 --- a/src/Handle.jsx +++ b/src/Handle.jsx @@ -10,6 +10,18 @@ export default class Handle extends React.Component { }; } + showTooltip() { + this.setState({ + isTooltipVisible: true, + }); + } + + hideTooltip() { + this.setState({ + isTooltipVisible: false, + }); + } + render() { const props = this.props; const {className, tipTransitionName, offset, value} = props; @@ -36,17 +48,6 @@ export default class Handle extends React.Component { {handle} ); } - - showTooltip() { - this.setState({ - isTooltipVisible: true, - }); - } - hideTooltip() { - this.setState({ - isTooltipVisible: false, - }); - } } Handle.propTypes = { diff --git a/src/Slider.jsx b/src/Slider.jsx index 1555004..9ea885e 100644 --- a/src/Slider.jsx +++ b/src/Slider.jsx @@ -30,46 +30,62 @@ function pauseEvent(e) { } } -function getValueFromIndex(props) { - const marksLen = props.marks.length; - const index = ('index' in props ? props.index : props.defaultIndex); - - let value; - if (marksLen > 0) { - value = ((props.max - props.min) / (marksLen - 1)) * (index); - value = value.toFixed(5); - } - return value; -} - class Slider extends React.Component { constructor(props) { super(props); - // Note: Maybe `value` is `0`, `false` and so on. - // So, check the existence of `value` with `in`. - let value = ('value' in props ? props.value : props.defaultValue); - value = this._trimAlignValue(value); + let upperBound; + let lowerBound; + if (props.range) { + const values = (props.values || props.defaultValues); + upperBound = this.trimAlignValue(values[1]); + lowerBound = this.trimAlignValue(values[0]); + } else if (props.marks.length > 0) { + upperBound = this.calcValueFromProps(props); + } else { + // Note: Maybe `value` is `0`. + // So, check the existence of `value` with `in`. + const value = ('value' in props ? props.value : props.defaultValue); + upperBound = this.trimAlignValue(value); + } - const marksLen = props.marks.length; - if (marksLen > 0) { - value = getValueFromIndex(props); + let recent; + if (props.range && upperBound === lowerBound) { + if (lowerBound === props.max) { + recent = 'lowerBound'; + } + if (upperBound === props.min) { + recent = 'upperBound'; + } + } else { + recent = 'upperBound'; } this.state = { - dragging: false, - value: value, + handle: null, + recent: recent, + upperBound: upperBound, + // If Slider is not range, set `lowerBound` equal to `min`. + lowerBound: (lowerBound || props.min), }; } componentWillReceiveProps(nextProps) { - if ('value' in nextProps) { + if (nextProps.range) { + const values = nextProps.values; + if (values) { + this.setState({ + upperBound: values[1], + lowerBound: values[0], + }); + } + } else if ('value' in nextProps) { this.setState({ - value: nextProps.value, + upperBound: nextProps.value, }); } else if ('index' in nextProps) { this.setState({ - value: getValueFromIndex(nextProps), + upperBound: this.calcValueFromProps(nextProps), }); } } @@ -94,19 +110,24 @@ class Slider extends React.Component { const props = this.props; const state = this.state; - let value = state.value; - const oldValue = value; - const diffPosition = position - this.startPosition; - const diffValue = diffPosition / this.getSliderLength() * (props.max - props.min); - value = this._trimAlignValue(this.startValue + diffValue); - if (value !== oldValue && !('value' in props) && !('index' in props)) { - this.setState({value: value}); + const value = this.trimAlignValue(this.startValue + diffValue); + const oldValue = state[state.handle]; + if (value === oldValue) return; + + if (!('value' in props) && !('index' in props)) { + this.setState({[state.handle]: value}); } - if (value !== oldValue) { - this._triggerEvents('onChange', value); + + if (props.range) { + // `this.state` will not be updated immediately after `this.setState`. + // So, create a similar object. + const data = Object.assign({}, state, {[state.handle]: value}); + this.triggerEvents('onChange', [data.lowerBound, data.upperBound]); + } else { + this.triggerEvents('onChange', value); } } @@ -114,30 +135,52 @@ class Slider extends React.Component { if (isNotTouchEvent(e)) return; const position = getTouchPosition(e); - const value = this._calValueByPos(position); - this._triggerEvents('onChange', value); - this._start(position, value); - this._addDocumentEvents('touch'); + this.onStart(position); + this.addDocumentEvents('touch'); pauseEvent(e); } onSliderMouseDown(e) { const position = getMousePosition(e); - const value = this._calValueByPos(position); - this._triggerEvents('onChange', value); - this._start(position, value); - this._addDocumentEvents('mouse'); + this.onStart(position); + this.addDocumentEvents('mouse'); pauseEvent(e); } - getIndex(v) { - const props = this.props; - const value = v === undefined ? this.state.value : v; + onStart(position) { + this.triggerEvents('onBeforeChange'); - if (props.marks.length === 0) { - return Math.floor((value - props.min) / props.step); + const value = this.calcValueByPos(position); + this.startValue = value; + this.startPosition = position; + + const {upperBound, lowerBound} = this.state; + const isUpperBoundCloser = Math.abs(upperBound - value) < Math.abs(lowerBound - value); + let valueNeedChanging = (!this.props.range || isUpperBoundCloser) ? 'upperBound' : 'lowerBound'; + const isAtTheSamePoint = (upperBound === lowerBound); + valueNeedChanging = isAtTheSamePoint ? this.state.recent : valueNeedChanging; + + this.setState({ + handle: valueNeedChanging, + recent: valueNeedChanging, + [valueNeedChanging]: value, + }); + + if (this.props.range) { + const data = Object.assign({}, this.state, {[valueNeedChanging]: value}); + this.triggerEvents('onChange', [data.lowerBound, data.upperBound]); + } else { + this.triggerEvents('onChange', value); } - const unit = ((props.max - props.min) / (props.marks.length - 1)).toFixed(5); + } + + getIndex(value) { + const {marks, min, max, step} = this.props; + + if (marks.length === 0) { + return Math.floor((value - min) / step); + } + const unit = ((max - min) / (marks.length - 1)).toFixed(5); return Math.round(value / unit); } @@ -157,71 +200,25 @@ class Slider extends React.Component { return rect.left; } - render() { - const state = this.state; - const {value, dragging} = state; + trimAlignValue(v) { + const state = this.state || {}; const props = this.props; - const {className, prefixCls, disabled, isIncluded, withDots} = props; - const {marks, step, max, min, tipTransitionName, children} = props; - const marksLen = marks.length; - - const sliderClassName = rcUtil.classSet({ - [prefixCls]: true, - [prefixCls + '-disabled']: disabled, - [className]: !!className, - }); - - const offset = this._calcOffset(value); - - let track = null; - if (isIncluded) { - const trackClassName = prefixCls + '-track'; - track = ; - } - - const handleClassName = prefixCls + '-handle'; - - let steps = null; - if (marksLen > 0 || (step > 1 && withDots)) { - const stepsClassName = prefixCls + '-step'; - const stepNum = marksLen > 0 ? marksLen : Math.floor((max - min) / step) + 1; - steps = (); - } - - let mark = null; - if (marksLen > 0) { - const markClassName = prefixCls + '-mark'; - mark = (); - } - - return ( -
- {track} - 0} /> - {steps} - {mark} - {children} -
- ); - } - - _trimAlignValue(v, propsArg) { - let val = v; - const props = propsArg || this.props; const {marks, min, max} = props; const step = marks.length > 0 ? (max - min) / (marks.length - 1) : props.step; + let val = v; if (val <= min) { val = min; } if (val >= max) { val = max; } + if (state.handle === 'upperBound' && val <= state.lowerBound) { + val = state.lowerBound; + } + if (state.handle === 'lowerBound' && val >= state.upperBound) { + val = state.upperBound; + } const valModStep = (val - min) % step; let alignValue = val - valModStep; @@ -233,28 +230,36 @@ class Slider extends React.Component { return parseFloat(alignValue.toFixed(5)); } - _calcOffset(value) { + calcOffset(value) { const {min, max} = this.props; const ratio = (value - min) / (max - min); return ratio * 100; } - _calcValue(offset) { + calcValue(offset) { const {min, max} = this.props; const ratio = offset / this.getSliderLength(); return ratio * (max - min) + min; } - _calValueByPos(position) { + calcValueByPos(position) { const pixelOffset = position - this.getSliderStart(); - const nextValue = this._trimAlignValue(this._calcValue(pixelOffset)); - this.setState({ - value: nextValue, - }); + const nextValue = this.trimAlignValue(this.calcValue(pixelOffset)); return nextValue; } - _triggerEvents(event, v) { + calcValueFromProps(props) { + const marksLen = props.marks.length; + if (marksLen > 0) { + const index = ('index' in props ? props.index : props.defaultIndex); + const value = ((props.max - props.min) / (marksLen - 1)) * (index); + // `'1' / 1 => 1`, to make sure that the returned value is a `Number`. + return value.toFixed(5) / 1; + } + return ('value' in props ? props.value : props.defaultValue); + } + + triggerEvents(event, v) { const props = this.props; const hasMarks = (props.marks.length > 0); if (props[event]) { @@ -270,7 +275,7 @@ class Slider extends React.Component { } } - _addDocumentEvents(type) { + addDocumentEvents(type) { if (type === 'touch') { // just work for chrome iOS Safari and Android Browser this.onTouchMoveListener = DomUtils.addEventListener(document, 'touchmove', this.onTouchMove.bind(this)); @@ -281,7 +286,7 @@ class Slider extends React.Component { } } - _removeEventons(type) { + removeEventons(type) { if (type === 'touch') { this.onTouchMoveListener.remove(); this.onTouchUpListener.remove(); @@ -291,21 +296,75 @@ class Slider extends React.Component { } } - _start(position, value) { - this._triggerEvents('onBeforeChange'); - this.startValue = value; - this.startPosition = position; - this.setState({ - dragging: true, - }); + end(type) { + this.removeEventons(type); + this.triggerEvents('onAfterChange'); + this.setState({ handle: null }); } - end(type) { - this._removeEventons(type); - this._triggerEvents('onAfterChange'); - this.setState({ - dragging: false, + render() { + const {handle, upperBound, lowerBound} = this.state; + const props = this.props; + const {className, prefixCls, disabled, isIncluded, withDots, range} = props; + const {marks, step, max, min, tipTransitionName, children} = props; + const marksLen = marks.length; + + const sliderClassName = rcUtil.classSet({ + [prefixCls]: true, + [prefixCls + '-disabled']: disabled, + [className]: !!className, }); + + const upperOffset = this.calcOffset(upperBound); + const lowerOffset = this.calcOffset(lowerBound); + + let track = null; + if (isIncluded || range) { + const trackClassName = prefixCls + '-track'; + track = ; + } + + const handleClassName = prefixCls + '-handle'; + const isNoTip = marksLen > 0; + const upper = (); + + let lower = null; + if (range) { + lower = (); + } + + const upperIndex = this.getIndex(upperBound); + + let steps = null; + if (marksLen > 0 || (step > 1 && withDots)) { + const stepsClassName = prefixCls + '-step'; + const stepNum = marksLen > 0 ? marksLen : Math.floor((max - min) / step) + 1; + steps = (); + } + + let mark = null; + if (marksLen > 0) { + const markClassName = prefixCls + '-mark'; + mark = (); + } + + return ( +
+ {track} + {upper} + {lower} + {steps} + {mark} + {children} +
+ ); } } @@ -314,8 +373,10 @@ Slider.propTypes = { max: React.PropTypes.number, step: React.PropTypes.number, defaultValue: React.PropTypes.number, + defaultValues: React.PropTypes.arrayOf(React.PropTypes.number), defaultIndex: React.PropTypes.number, value: React.PropTypes.number, + values: React.PropTypes.arrayOf(React.PropTypes.number), index: React.PropTypes.number, marks: React.PropTypes.array, isIncluded: React.PropTypes.bool, @@ -328,6 +389,7 @@ Slider.propTypes = { onAfterChange: React.PropTypes.func, tipTransitionName: React.PropTypes.string, withDots: React.PropTypes.bool, + range: React.PropTypes.bool, }; Slider.defaultProps = { @@ -335,6 +397,7 @@ Slider.defaultProps = { max: 100, step: 1, defaultValue: 0, + defaultValues: [0, 0], defaultIndex: 0, marks: [], isIncluded: true, @@ -343,6 +406,7 @@ Slider.defaultProps = { disabled: false, tipTransitionName: '', withDots: false, + range: false, }; export default Slider; diff --git a/src/Steps.jsx b/src/Steps.jsx index dc49d2d..ea7ec08 100644 --- a/src/Steps.jsx +++ b/src/Steps.jsx @@ -1,7 +1,7 @@ import React from 'react'; import rcUtil from 'rc-util'; -const Steps = ({className, stepNum, isIncluded, index}) => { +const Steps = ({className, stepNum, isIncluded, lowerIndex, upperIndex}) => { const dotClassName = className.replace('step', 'dot'); const unit = 100 / (stepNum - 1); @@ -10,7 +10,8 @@ const Steps = ({className, stepNum, isIncluded, index}) => { const offset = unit * i + '%'; const style = { left: offset }; - const isActived = (isIncluded && i <= index) || (!isIncluded && i === index); + const isActived = (isIncluded && i <= upperIndex && i >= lowerIndex ) || + (!isIncluded && i === upperIndex); const stepClassName = rcUtil.classSet({ [dotClassName]: true, [dotClassName + '-active']: isActived, diff --git a/tests/index.spec.js b/tests/index.spec.js index 8c18335..b2b5057 100644 --- a/tests/index.spec.js +++ b/tests/index.spec.js @@ -26,7 +26,7 @@ describe('rc-slider', function () { expect(node.find('.rc-slider').length).to.be(1); expect(node.find('.rc-slider-handle').length).to.be(1); expect(node.find('.rc-slider-track').length).to.be(1); - expect(slider.state.value).to.be(40); + expect(slider.state.upperBound).to.be(40); var trackWidth = node.find('.rc-slider-track')[0].style.width; expect(trackWidth).to.eql(node.find('.rc-slider-handle')[0].style.left); }); @@ -40,7 +40,7 @@ describe('rc-slider', function () { expect(node.find('.rc-slider').length).to.be(1); expect(node.find('.rc-slider-handle').length).to.be(1); expect(node.find('.rc-slider-track').length).to.be(1); - expect(slider.state.value).to.be(0); + expect(slider.state.upperBound).to.be(0); var sliderWithDots = React.render( , @@ -62,7 +62,7 @@ describe('rc-slider', function () { expect(node.find('.rc-slider-dot').length).to.be(slider.props.marks.length); expect(node.find('.rc-slider-mark').length).to.be(1); expect(node.find('.rc-slider-mark-text').length).to.be(slider.props.marks.length); - expect(slider.getIndex()).to.be(3); + expect(slider.getIndex(slider.state.upperBound)).to.be(3); }); // it('should mouseDown works!', function (done) {