diff --git a/components/vc-slider/demo/handle.jsx b/components/vc-slider/demo/handle.jsx index fd812ed61..b2af8e3ff 100644 --- a/components/vc-slider/demo/handle.jsx +++ b/components/vc-slider/demo/handle.jsx @@ -3,16 +3,22 @@ import Tooltip from '../../vc-tooltip' import '../assets/index.less' import '../../vc-tooltip/assets/bootstrap.less' -const { createSliderWithTooltip, Handle } = Slider -const Range = createSliderWithTooltip(Slider.Range) +const { Handle, Range } = Slider export default { data () { return { + visibles: [], } }, + methods: { + handleTooltipVisibleChange (index, visible) { + this.visibles[index] = visible + this.visibles = { ...this.visibles } + }, + }, render () { - const handle = (props) => { + const handle = (h, props) => { const { value, dragging, index, refStr, ...restProps } = props const handleProps = { props: { @@ -32,10 +38,66 @@ export default { placement='top' key={index} > + ) } + + const handleRange = (h, { value, dragging, index, disabled, ...restProps }) => { + const tipFormatter = value => `${value}%` + const handleStyle = [{}] + const tipProps = {} + + const { + prefixCls = 'rc-slider-tooltip', + overlay = tipFormatter(value), + placement = 'top', + visible = visible || false, + ...restTooltipProps } = tipProps + + let handleStyleWithIndex + if (Array.isArray(handleStyle)) { + handleStyleWithIndex = handleStyle[index] || handleStyle[0] + } else { + handleStyleWithIndex = handleStyle + } + + const tooltipProps = { + props: { + prefixCls, + overlay, + placement, + visible: (!disabled && (this.visibles[index] || dragging)) || visible, + ...restTooltipProps, + }, + key: index, + } + const handleProps = { + props: { + value, + ...restProps, + }, + on: { + mouseenter: () => this.handleTooltipVisibleChange(index, true), + mouseleave: () => this.handleTooltipVisibleChange(index, false), + }, + style: { + ...handleStyleWithIndex, + }, + } + + return ( + + + + + ) + } const wrapperStyle = 'width: 400px; margin: 50px' return ( @@ -44,10 +106,10 @@ export default {

Slider with custom handle

- {/*
+

Range with custom handle

- `${value}%`} /> -
*/} + +
) }, diff --git a/components/vc-slider/src/Handle.jsx b/components/vc-slider/src/Handle.jsx index 4d8d7c800..b8386d59f 100644 --- a/components/vc-slider/src/Handle.jsx +++ b/components/vc-slider/src/Handle.jsx @@ -1,8 +1,12 @@ import PropTypes from '../../_util/vue-types' import addEventListener from '../../_util/Dom/addEventListener' import BaseMixin from '../../_util/BaseMixin' +import { getOptionProps } from '../../_util/props-util' + +function noop () {} export default { + name: 'Handle', mixins: [BaseMixin], props: { prefixCls: PropTypes.string, @@ -14,6 +18,8 @@ export default { value: PropTypes.number, tabIndex: PropTypes.number, refStr: PropTypes.any, + handleFocus: PropTypes.func.def(noop), + handleBlur: PropTypes.func.def(noop), }, data () { return { @@ -22,6 +28,8 @@ export default { }, mounted () { this.$nextTick(() => { + // mouseup won't trigger if mouse moved out of handle, + // so we listen on document here. this.onMouseUpListener = addEventListener(document, 'mouseup', this.handleMouseUp) this.refStr = this.$props.refStr }) @@ -42,8 +50,12 @@ export default { this.setClickFocus(true) } }, - handleBlur () { + onBlur (e) { this.setClickFocus(false) + this.handleBlur(e) + }, + onFocus (e) { + this.handleFocus(e) }, handleKeyDown () { this.setClickFocus(false) @@ -61,8 +73,8 @@ export default { }, render () { const { - prefixCls, vertical, offset, disabled, min, max, value, tabIndex, refStr, ...restProps - } = this.$props + prefixCls, vertical, offset, disabled, min, max, value, tabIndex, refStr, + } = getOptionProps(this) const className = { [`${prefixCls}-handle`]: true, @@ -89,13 +101,14 @@ export default { tabIndex: disabled ? null : (tabIndex || 0), refStr, ...ariaProps, - ...restProps, }, style: elStyle, class: className, on: { - blur: this.handleBlur, + blur: this.onBlur, + focus: this.onFocus, keydown: this.handleKeyDown, + ...this.$listeners, }, ref: 'handle', } diff --git a/components/vc-slider/src/Range.jsx b/components/vc-slider/src/Range.jsx index f0cfa1ce2..1d3c0797c 100644 --- a/components/vc-slider/src/Range.jsx +++ b/components/vc-slider/src/Range.jsx @@ -19,6 +19,7 @@ const rangeProps = { tabIndex: PropTypes.arrayOf(PropTypes.number), } const Range = { + name: 'Range', displayName: 'Range', mixins: [BaseMixin], props: initDefaultProps(rangeProps, { @@ -39,7 +40,7 @@ const Range = { const bounds = value.map((v, i) => this.trimAlignValue(v, i)) const recent = bounds[0] === max ? 0 : bounds.length - 1 return { - handle: null, + sHandle: null, recent, bounds, } @@ -86,7 +87,7 @@ const Range = { if (isNotControlled) { this.setState(state) } else if (state.handle !== undefined) { - this.setState({ handle: state.handle }) + this.setState({ sHandle: state.handle }) } const data = { ...this.$data, ...state } @@ -103,7 +104,7 @@ const Range = { this.prevMovedHandleIndex = this.getBoundNeedMoving(value, closestBound) this.setState({ - handle: this.prevMovedHandleIndex, + sHandle: this.prevMovedHandleIndex, recent: this.prevMovedHandleIndex, }) @@ -115,14 +116,15 @@ const Range = { this.$emit('change', { bounds: nextBounds }) }, onEnd () { + this.setState({ sHandle: null }) this.removeDocumentEvents() this.$emit('afterChange', this.bounds) }, onMove (e, position) { utils.pauseEvent(e) - const { bounds, handle } = this + const { bounds, sHandle } = this const value = this.calcValueByPos(position) - const oldValue = bounds[handle] + const oldValue = bounds[sHandle] if (value === oldValue) return this.moveTo(value) @@ -132,8 +134,8 @@ const Range = { if (valueMutator) { utils.pauseEvent(e) - const { bounds, handle } = this - const oldValue = bounds[handle] + const { bounds, sHandle } = this + const oldValue = bounds[sHandle] const mutatedValue = valueMutator(oldValue, this.$props) const value = this.trimAlignValue(mutatedValue) if (value === oldValue) return @@ -194,18 +196,18 @@ const Range = { return this._getPointsCache.points }, moveTo (value, isFromKeyboardEvent) { - const { bounds, handle } = this + const { bounds, sHandle } = this const nextBounds = [...bounds] - nextBounds[handle] = value - let nextHandle = handle + nextBounds[sHandle] = value + let nextHandle = sHandle if (this.pushable !== false) { this.pushSurroundingHandles(nextBounds, nextHandle) } else if (this.allowCross) { nextBounds.sort((a, b) => a - b) nextHandle = nextBounds.indexOf(value) } - this.$emit('change', { - handle: nextHandle, + this.onChange({ + sHandle: nextHandle, bounds: nextBounds, }) if (isFromKeyboardEvent) { @@ -276,7 +278,7 @@ const Range = { return true }, trimAlignValue (v, handle, nextProps = {}) { - const mergedProps = { ...this, ...nextProps } + const mergedProps = { ...this.$props, ...nextProps } const valInRange = utils.ensureValueInRange(v, mergedProps) const valNotConflict = this.ensureValueNotConflict(handle, valInRange, mergedProps) return utils.ensureValuePrecision(valNotConflict, mergedProps) @@ -284,7 +286,7 @@ const Range = { ensureValueNotConflict (handle, val, { allowCross, pushable: thershold }) { const state = this.$data || {} const { bounds } = state - handle = handle === undefined ? state.handle : handle + handle = handle === undefined ? state.sHandle : handle thershold = Number(thershold) /* eslint-disable eqeqeq */ if (!allowCross && handle != null && bounds !== undefined) { @@ -298,65 +300,71 @@ const Range = { /* eslint-enable eqeqeq */ return val }, - }, - render () { - const { - handle, - bounds, - prefixCls, - vertical, - included, - disabled, - min, - max, - handle: handleGenerator, - trackStyle, - handleStyle, - tabIndex, - } = this - - const offsets = bounds.map(v => this.calcOffset(v)) - - const handleClassName = `${prefixCls}-handle` - const handles = bounds.map((v, i) => handleGenerator({ - className: classNames({ - [handleClassName]: true, - [`${handleClassName}-${i + 1}`]: true, - }), - prefixCls, - vertical, - offset: offsets[i], - value: v, - dragging: handle === i, - index: i, - tabIndex: tabIndex[i] || 0, - min, - max, - disabled, - style: handleStyle[i], - refStr: 'handleRef' + i, - })) - - const tracks = bounds.slice(0, -1).map((_, index) => { - const i = index + 1 - const trackClassName = classNames({ - [`${prefixCls}-track`]: true, - [`${prefixCls}-track-${i}`]: true, + getTrack ({ bounds, prefixCls, vertical, included, offsets, trackStyle }) { + return bounds.slice(0, -1).map((_, index) => { + const i = index + 1 + const trackClassName = classNames({ + [`${prefixCls}-track`]: true, + [`${prefixCls}-track-${i}`]: true, + }) + return ( + + ) }) - return ( - - ) - }) + }, + renderSlider (h) { + const { + sHandle, + bounds, + prefixCls, + vertical, + included, + disabled, + min, + max, + handle: handleGenerator, + trackStyle, + handleStyle, + tabIndex, + } = this - return { tracks, handles } + const offsets = bounds.map(v => this.calcOffset(v)) + + const handleClassName = `${prefixCls}-handle` + const handles = bounds.map((v, i) => handleGenerator(h, { + className: classNames({ + [handleClassName]: true, + [`${handleClassName}-${i + 1}`]: true, + }), + prefixCls, + vertical, + offset: offsets[i], + value: v, + dragging: sHandle === i, + index: i, + tabIndex: tabIndex[i] || 0, + min, + max, + disabled, + style: handleStyle[i], + refStr: 'handleRef' + i, + handleFocus: this.onFocus, + handleBlur: this.onBlur, + })) + + return { + tracks: this.getTrack({ bounds, prefixCls, vertical, included, offsets, trackStyle }), + handles, + } + }, }, } diff --git a/components/vc-slider/src/Slider.jsx b/components/vc-slider/src/Slider.jsx index bf7c90b44..f8bbe4587 100644 --- a/components/vc-slider/src/Slider.jsx +++ b/components/vc-slider/src/Slider.jsx @@ -7,6 +7,7 @@ import createSlider from './common/createSlider' import * as utils from './utils' const Slider = { + name: 'Slider', mixins: [BaseMixin], props: { defaultValue: PropTypes.number, @@ -151,43 +152,45 @@ const Slider = { /> ) }, - }, - render () { - const { - prefixCls, - vertical, - included, - disabled, - minimumTrackStyle, - trackStyle, - handleStyle, - tabIndex, - min, - max, - handle: handleGenerator, - } = this - const { sValue, dragging } = this - const offset = this.calcOffset(sValue) - const handle = handleGenerator({ - prefixCls, - vertical, - offset, - value: sValue, - dragging, - disabled, - min, - max, - index: 0, - tabIndex, - style: handleStyle[0] || handleStyle, - refStr: 'handleRef0', - }) + renderSlider (h) { + const { + prefixCls, + vertical, + included, + disabled, + minimumTrackStyle, + trackStyle, + handleStyle, + tabIndex, + min, + max, + handle: handleGenerator, + } = this + const { sValue, dragging } = this + const offset = this.calcOffset(sValue) + const handle = handleGenerator(h, { + prefixCls, + vertical, + offset, + value: sValue, + dragging, + disabled, + min, + max, + index: 0, + tabIndex, + style: handleStyle[0] || handleStyle, + refStr: 'handleRef0', + handleFocus: this.onFocus, + handleBlur: this.onBlur, + }) - const _trackStyle = trackStyle[0] || trackStyle - return { - tracks: this.getTrack({ prefixCls, vertical, included, offset, minimumTrackStyle, _trackStyle }), - handles: handle, - } + const _trackStyle = trackStyle[0] || trackStyle + return { + tracks: this.getTrack({ prefixCls, vertical, included, offset, minimumTrackStyle, _trackStyle }), + handles: handle, + } + }, }, } diff --git a/components/vc-slider/src/common/createSlider.jsx b/components/vc-slider/src/common/createSlider.jsx index d8fb0f244..23ca08b78 100644 --- a/components/vc-slider/src/common/createSlider.jsx +++ b/components/vc-slider/src/common/createSlider.jsx @@ -34,6 +34,7 @@ export default function createSlider (Component) { autoFocus: PropTypes.bool, } return { + name: 'createSlider', mixins: [Component], props: initDefaultProps(propTypes, { ...Component.defaultProps, @@ -42,7 +43,7 @@ export default function createSlider (Component) { max: 100, step: 1, marks: {}, - handle ({ index, refStr, ...restProps }) { + handle (h, { index, refStr, className, ...restProps }) { delete restProps.dragging const handleProps = { props: { @@ -51,6 +52,7 @@ export default function createSlider (Component) { attrs: { refStr, }, + class: className, key: index, } return @@ -167,8 +169,11 @@ export default function createSlider (Component) { /* eslint-enable no-unused-expressions */ }, onMouseUp () { - if (this.handlesRefs[this.prevMovedHandleIndex]) { - this.handlesRefs[this.prevMovedHandleIndex].clickFocus() + if (this.$children && this.$children[this.prevMovedHandleIndex]) { + const handleCom = utils.getComponentProps(this.$children[this.prevMovedHandleIndex], 'clickFocus') + if (handleCom) { + handleCom.clickFocus() + } } }, onMouseMove (e) { @@ -239,7 +244,7 @@ export default function createSlider (Component) { this.$emit('change', { value }) }, }, - render () { + render (h) { const { prefixCls, marks, @@ -255,7 +260,7 @@ export default function createSlider (Component) { dotStyle, activeDotStyle, } = this - const { tracks, handles } = Component.render.call(this) + const { tracks, handles } = this.renderSlider(h) const sliderClassName = classNames(prefixCls, { [`${prefixCls}-with-marks`]: Object.keys(marks).length, diff --git a/components/vc-slider/src/createSliderWithTooltip.jsx b/components/vc-slider/src/createSliderWithTooltip.jsx index a315eceb5..93e11c4af 100644 --- a/components/vc-slider/src/createSliderWithTooltip.jsx +++ b/components/vc-slider/src/createSliderWithTooltip.jsx @@ -1,11 +1,12 @@ import PropTypes from '../../_util/vue-types' import BaseMixin from '../../_util/BaseMixin' import Tooltip from '../../vc-tooltip' +import { getOptionProps } from '../../_util/props-util' import Handle from './Handle' export default function createSliderWithTooltip (Component) { return { - mixins: [BaseMixin], + mixins: [BaseMixin, Component], props: { tipFormatter: PropTypes.func.def((value) => { return value }), handleStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.arrayOf(PropTypes.object)]).def([{}]), @@ -85,7 +86,13 @@ export default function createSliderWithTooltip (Component) { }, }, render () { - return + const componentProps = { + props: { + ...getOptionProps(this), + handle: this.handleWithTooltip, + }, + } + return }, } } diff --git a/components/vc-slider/src/utils.js b/components/vc-slider/src/utils.js index 170f2ccf1..594af75bd 100644 --- a/components/vc-slider/src/utils.js +++ b/components/vc-slider/src/utils.js @@ -89,3 +89,18 @@ export function getKeyboardValueMutator (e) { default: return undefined } } + +export function getComponentProps (obj, prop) { + if (obj[prop]) { + return obj + } else if (obj.$children.length) { + const len = obj.$children.length + for (let i = 0; i < len; i++) { + if (obj.$children[i][prop]) { + return obj.$children[i] + } else if (obj.$children[i].$children.length) { + return getComponentProps(obj.$children[i], prop) + } + } + } +} diff --git a/examples/routes.js b/examples/routes.js index 9ea148250..136f1b381 100644 --- a/examples/routes.js +++ b/examples/routes.js @@ -3,7 +3,7 @@ const AsyncComp = () => { const hashs = window.location.hash.split('/') const d = hashs[hashs.length - 1] return { - component: import(`../components/vc-table/demo/${d}`), + component: import(`../components/vc-slider/demo/${d}`), } } export default [