refactor and DRY Slider

This commit is contained in:
Sergio Crisostomo 2017-11-11 10:16:43 +01:00
parent e6a09eee33
commit 2b87ffa91a

View file

@ -14,34 +14,26 @@
<div :class="[prefixCls + '-stop']" v-for="item in stops" :style="{ 'left': item + '%' }" @click.self="sliderClick"></div> <div :class="[prefixCls + '-stop']" v-for="item in stops" :style="{ 'left': item + '%' }" @click.self="sliderClick"></div>
</template> </template>
<div :class="[prefixCls + '-bar']" :style="barStyle" @click.self="sliderClick"></div> <div :class="[prefixCls + '-bar']" :style="barStyle" @click.self="sliderClick"></div>
<template v-if="range">
<div <div
:class="[prefixCls + '-button-wrap']" :class="[prefixCls + '-button-wrap']"
:style="{left: firstPosition + '%'}" :style="{left: minPosition + '%'}"
@mousedown="onFirstButtonDown"> @touchstart="onPointerDown($event, 'min')"
<Tooltip :controlled="firstDragging" placement="top" :content="tipFormat(currentValue[0])" :disabled="tipDisabled" :always="showTip === 'always'" ref="tooltip"> @mousedown="onPointerDown($event, 'min')">
<div :class="button1Classes"></div> <Tooltip :controlled="pointerDown === 'min'" placement="top" :content="tipFormat(currentValue[0])"
:disabled="tipDisabled" :always="showTip === 'always'" ref="minTooltip">
<div :class="minButtonClasses"></div>
</Tooltip> </Tooltip>
</div> </div>
<div <div v-if="range"
:class="[prefixCls + '-button-wrap']" :class="[prefixCls + '-button-wrap']"
:style="{left: secondPosition + '%'}" :style="{left: maxPosition + '%'}"
@mousedown="onSecondButtonDown"> @touchstart="onPointerDown($event, 'max')"
<Tooltip :controlled="secondDragging" placement="top" :content="tipFormat(currentValue[1])" :disabled="tipDisabled" :always="showTip === 'always'" ref="tooltip2"> @mousedown="onPointerDown($event, 'max')">
<div :class="button2Classes"></div> <Tooltip :controlled="pointerDown === 'max'" placement="top" :content="tipFormat(currentValue[1])"
:disabled="tipDisabled" :always="showTip === 'always'" ref="maxTooltip">
<div :class="maxButtonClasses"></div>
</Tooltip> </Tooltip>
</div> </div>
</template>
<template v-else>
<div
:class="[prefixCls + '-button-wrap']"
:style="{left: singlePosition + '%'}"
@mousedown="onSingleButtonDown">
<Tooltip :controlled="dragging" placement="top" :content="tipFormat(currentValue)" :disabled="tipDisabled" :always="showTip === 'always'" ref="tooltip">
<div :class="buttonClasses"></div>
</Tooltip>
</div>
</template>
</div> </div>
</div> </div>
</template> </template>
@ -109,38 +101,36 @@
} }
}, },
data () { data () {
const val = this.checkLimits(Array.isArray(this.value) ? this.value : [this.value]);
return { return {
prefixCls: prefixCls, prefixCls: prefixCls,
currentValue: this.value, currentValue: val,
dragging: false, dragging: false,
firstDragging: false, pointerDown: '',
secondDragging: false,
startX: 0, startX: 0,
currentX: 0, currentX: 0,
startPos: 0, startPos: 0,
newPos: null, newPos: null,
oldSingleValue: this.value, oldValue: val
oldFirstValue: this.value[0],
oldSecondValue: this.value[1],
singlePosition: (this.value - this.min) / (this.max - this.min) * 100,
firstPosition: (this.value[0] - this.min) / (this.max - this.min) * 100,
secondPosition: (this.value[1] - this.min) / (this.max - this.min) * 100
}; };
}, },
watch: { watch: {
value (val) { value (val) {
val = this.checkLimits(Array.isArray(val) ? val : [val]);
if (val[0] !== this.currentValue[0] || val[1] !== this.currentValue[1]) {
this.currentValue = val; this.currentValue = val;
}
}, },
currentValue (val) { currentValue (val) {
this.$nextTick(() => { this.$nextTick(() => {
this.$refs.tooltip.updatePopper(); this.$refs.minTooltip.updatePopper();
if (this.range) { if (this.range) {
this.$refs.tooltip2.updatePopper(); this.$refs.maxTooltip.updatePopper();
} }
}); });
this.updateValue(val); const exportValue = this.range ? val : val[0];
this.$emit('input', val); this.$emit('input', exportValue);
this.$emit('on-input', val); this.$emit('on-input', exportValue);
} }
}, },
computed: { computed: {
@ -154,42 +144,38 @@
} }
]; ];
}, },
buttonClasses () { minButtonClasses () {
return [ return [
`${prefixCls}-button`, `${prefixCls}-button`,
{ {
[`${prefixCls}-button-dragging`]: this.dragging [`${prefixCls}-button-dragging`]: this.pointerDown === 'min'
} }
]; ];
}, },
button1Classes () { maxButtonClasses () {
return [ return [
`${prefixCls}-button`, `${prefixCls}-button`,
{ {
[`${prefixCls}-button-dragging`]: this.firstDragging [`${prefixCls}-button-dragging`]: this.pointerDown === 'max'
} }
]; ];
}, },
button2Classes () { minPosition () {
return [ const val = this.currentValue;
`${prefixCls}-button`, return (val[0] - this.min) / (this.max - this.min) * 100;
{ },
[`${prefixCls}-button-dragging`]: this.secondDragging maxPosition: function () {
} const val = this.currentValue;
];
return (val[1] - this.min) / (this.max - this.min) * 100;
}, },
barStyle () { barStyle () {
let style; const style = {
if (this.range) {
style = {
width: (this.currentValue[1] - this.currentValue[0]) / (this.max - this.min) * 100 + '%',
left: (this.currentValue[0] - this.min) / (this.max - this.min) * 100 + '%' left: (this.currentValue[0] - this.min) / (this.max - this.min) * 100 + '%'
}; };
} else {
style = { if (this.range) {
width: (this.currentValue - this.min) / (this.max - this.min) * 100 + '%' style.width = (this.currentValue[1] - this.currentValue[0]) / (this.max - this.min) * 100 + '%';
};
} }
return style; return style;
@ -211,268 +197,97 @@
} }
}, },
methods: { methods: {
updateValue (val, init = false) { getPointerX (e) {
if (this.range) { return e.type.indexOf('touch') !== -1 ? e.touches[0].clientX : e.clientX;
let value = [...val]; },
if (init) { checkLimits ([min, max]) {
if (value[0] > value[1]) { min = Math.max(0, min);
value = [this.min, this.max]; min = Math.min(100, min);
}
} else { max = Math.max(0, min, max);
if (value[0] > value[1]) { max = Math.min(100, max);
value[0] = value[1]; return [min, max];
} },
} onPointerDown (event, type) {
if (value[0] < this.min) { if (this.disabled) return;
value[0] = this.min; event.preventDefault();
} this.pointerDown = type;
if (value[0] > this.max) {
value[0] = this.max; this.onPointerDragStart(event);
} on(window, 'mousemove', this.onPointerDrag);
if (value[1] < this.min) { on(window, 'touchmove', this.onPointerDrag);
value[1] = this.min; on(window, 'mouseup', this.onPointerDragEnd);
} on(window, 'touchend', this.onPointerDragEnd);
if (value[1] > this.max) { },
value[1] = this.max; onPointerDragStart (event) {
} this.dragging = false;
if (this.value[0] === value[0] && this.value[1] === value[1]) { this.startX = this.getPointerX(event);
this.setFirstPosition(this.currentValue[0]); this.startPos = parseInt(this[`${this.pointerDown}Position`], 10);
this.setSecondPosition(this.currentValue[1]); },
return; onPointerDrag (event) {
this.dragging = true;
this.$refs[`${this.pointerDown}Tooltip`].visible = true;
this.currentX = this.getPointerX(event);
const diff = (this.currentX - this.startX) / this.sliderWidth * 100;
this.newPos = this.startPos + diff;
this.changeButtonPosition(this.newPos);
},
onPointerDragEnd () {
if (this.dragging) {
this.dragging = false;
this.$refs[`${this.pointerDown}Tooltip`].visible = false;
this.changeButtonPosition(this.newPos);
} }
this.currentValue = value; this.pointerDown = '';
this.setFirstPosition(this.currentValue[0]); off(window, 'mousemove', this.onPointerDrag);
this.setSecondPosition(this.currentValue[1]); off(window, 'touchmove', this.onPointerDrag);
} else { off(window, 'mouseup', this.onPointerDragEnd);
if (val < this.min) { off(window, 'touchend', this.onPointerDragEnd);
this.currentValue = this.min; },
changeButtonPosition (newPos, forceType) {
const type = forceType || this.pointerDown;
const index = type === 'min' ? 0 : 1;
if (type === 'min') newPos = this.checkLimits([newPos, this.maxPosition])[0];
else newPos = this.checkLimits([this.minPosition, newPos])[1];
const lengthPerStep = 100 / ((this.max - this.min) / this.step);
const steps = Math.round(newPos / lengthPerStep);
const value = this.currentValue;
value[index] = Math.round(steps * lengthPerStep * (this.max - this.min) * 0.01 + this.min);
this.currentValue = [...value];
if (!this.dragging) {
if (this.currentValue[index] !== this.oldValue[index]) {
const exportValue = this.range ? this.currentValue : this.currentValue[0];
this.$emit('on-change', exportValue);
this.dispatch('FormItem', 'on-form-change', exportValue);
this.oldValue[index] = this.currentValue[index];
} }
if (val > this.max) {
this.currentValue = this.max;
}
this.setSinglePosition(this.currentValue);
} }
}, },
sliderClick (event) {
sliderClick: function (event) {
if (this.disabled) return; if (this.disabled) return;
const currentX = event.clientX; const currentX = this.getPointerX(event);
const sliderOffsetLeft = this.$refs.slider.getBoundingClientRect().left; const sliderOffsetLeft = this.$refs.slider.getBoundingClientRect().left;
const newPos = (currentX - sliderOffsetLeft) / this.sliderWidth * 100; const newPos = (currentX - sliderOffsetLeft) / this.sliderWidth * 100;
if (this.range) { if (!this.range || newPos <= this.minPosition) this.changeButtonPosition(newPos, 'min');
let type = ''; else if (newPos >= this.maxPosition) this.changeButtonPosition(newPos, 'max');
if (newPos <= this.firstPosition) { else this.changeButtonPosition(newPos, ((newPos - this.firstPosition) <= (this.secondPosition - newPos)) ? 'min' : 'max');
type = 'First';
} else if (newPos >= this.secondPosition) {
type = 'Second';
} else {
if ((newPos - this.firstPosition) <= (this.secondPosition - newPos)) {
type = 'First';
} else {
type = 'Second';
}
}
this[`change${type}Position`](newPos);
} else {
this.changeSinglePosition(newPos);
}
}, },
// for single use
onSingleButtonDown (event) {
if (this.disabled) return;
event.preventDefault();
this.onSingleDragStart(event);
// window.addEventListener('mousemove', this.onSingleDragging);
// window.addEventListener('mouseup', this.onSingleDragEnd);
on(window, 'mousemove', this.onSingleDragging);
on(window, 'mouseup', this.onSingleDragEnd);
},
onSingleDragStart (event) {
this.dragging = false;
this.startX = event.clientX;
this.startPos = parseInt(this.singlePosition, 10);
},
onSingleDragging (event) {
this.dragging = true;
if (this.dragging) {
this.$refs.tooltip.visible = true;
this.currentX = event.clientX;
const diff = (this.currentX - this.startX) / this.sliderWidth * 100;
this.newPos = this.startPos + diff;
this.changeSinglePosition(this.newPos);
}
},
onSingleDragEnd () {
if (this.dragging) {
this.dragging = false;
this.$refs.tooltip.visible = false;
this.changeSinglePosition(this.newPos);
// window.removeEventListener('mousemove', this.onSingleDragging);
// window.removeEventListener('mouseup', this.onSingleDragEnd);
}
off(window, 'mousemove', this.onSingleDragging);
off(window, 'mouseup', this.onSingleDragEnd);
},
changeSinglePosition (newPos) {
if (newPos < 0) {
newPos = 0;
} else if (newPos > 100) {
newPos = 100;
}
const lengthPerStep = 100 / ((this.max - this.min) / this.step);
const steps = Math.round(newPos / lengthPerStep);
this.currentValue = Math.round(steps * lengthPerStep * (this.max - this.min) * 0.01 + this.min);
this.setSinglePosition(this.currentValue);
if (!this.dragging) {
if (this.currentValue !== this.oldSingleValue) {
this.$emit('on-change', this.currentValue);
this.dispatch('FormItem', 'on-form-change', this.currentValue);
this.oldSingleValue = this.currentValue;
}
}
},
setSinglePosition (val) {
this.singlePosition = (val - this.min) / (this.max - this.min) * 100;
},
handleInputChange (val) { handleInputChange (val) {
this.currentValue = val; this.currentValue = [val, this.currentValue[1]];
this.setSinglePosition(val); const exportValue = this.range ? this.currentValue : this.currentValue[0];
this.$emit('on-change', this.currentValue); this.$emit('on-change', exportValue);
this.dispatch('FormItem', 'on-form-change', this.currentValue); this.dispatch('FormItem', 'on-form-change', exportValue);
}, },
// for range use first
onFirstButtonDown (event) {
if (this.disabled) return;
event.preventDefault();
this.onFirstDragStart(event);
// window.addEventListener('mousemove', this.onFirstDragging);
// window.addEventListener('mouseup', this.onFirstDragEnd);
on(window, 'mousemove', this.onFirstDragging);
on(window, 'mouseup', this.onFirstDragEnd);
},
onFirstDragStart (event) {
this.firstDragging = false;
this.startX = event.clientX;
this.startPos = parseInt(this.firstPosition, 10);
},
onFirstDragging (event) {
this.firstDragging = true;
if (this.firstDragging) {
this.$refs.tooltip.visible = true;
this.currentX = event.clientX;
const diff = (this.currentX - this.startX) / this.sliderWidth * 100;
this.newPos = this.startPos + diff;
this.changeFirstPosition(this.newPos);
}
},
onFirstDragEnd () {
if (this.firstDragging) {
this.firstDragging = false;
this.$refs.tooltip.visible = false;
this.changeFirstPosition(this.newPos);
// window.removeEventListener('mousemove', this.onFirstDragging);
// window.removeEventListener('mouseup', this.onFirstDragEnd);
}
off(window, 'mousemove', this.onFirstDragging);
off(window, 'mouseup', this.onFirstDragEnd);
},
changeFirstPosition (newPos) {
if (newPos < 0) {
newPos = 0;
} else if (newPos > this.secondPosition) {
newPos = this.secondPosition;
}
const lengthPerStep = 100 / ((this.max - this.min) / this.step);
const steps = Math.round(newPos / lengthPerStep);
this.currentValue = [Math.round(steps * lengthPerStep * (this.max - this.min) * 0.01 + this.min), this.currentValue[1]];
this.setFirstPosition(this.currentValue[0]);
if (!this.firstDragging) {
if (this.currentValue[0] !== this.oldFirstValue) {
this.$emit('on-change', this.currentValue);
this.dispatch('FormItem', 'on-form-change', this.currentValue);
this.oldFirstValue = this.currentValue[0];
}
}
},
setFirstPosition (val) {
this.firstPosition = (val - this.min) / (this.max - this.min) * 100;
},
// for range use second
onSecondButtonDown (event) {
if (this.disabled) return;
event.preventDefault();
this.onSecondDragStart(event);
// window.addEventListener('mousemove', this.onSecondDragging);
// window.addEventListener('mouseup', this.onSecondDragEnd);
on(window, 'mousemove', this.onSecondDragging);
on(window, 'mouseup', this.onSecondDragEnd);
},
onSecondDragStart (event) {
this.secondDragging = false;
this.startX = event.clientX;
this.startPos = parseInt(this.secondPosition, 10);
},
onSecondDragging (event) {
this.secondDragging = true;
if (this.secondDragging) {
this.$refs.tooltip2.visible = true;
this.currentX = event.clientX;
const diff = (this.currentX - this.startX) / this.sliderWidth * 100;
this.newPos = this.startPos + diff;
this.changeSecondPosition(this.newPos);
}
},
onSecondDragEnd () {
if (this.secondDragging) {
this.secondDragging = false;
this.$refs.tooltip2.visible = false;
this.changeSecondPosition(this.newPos);
// window.removeEventListener('mousemove', this.onSecondDragging);
// window.removeEventListener('mouseup', this.onSecondDragEnd);
}
off(window, 'mousemove', this.onSecondDragging);
off(window, 'mouseup', this.onSecondDragEnd);
},
changeSecondPosition (newPos) {
if (newPos > 100) {
newPos = 100;
} else if (newPos < this.firstPosition) {
newPos = this.firstPosition;
}
const lengthPerStep = 100 / ((this.max - this.min) / this.step);
const steps = Math.round(newPos / lengthPerStep);
this.currentValue = [this.currentValue[0], Math.round(steps * lengthPerStep * (this.max - this.min) * 0.01 + this.min)];
this.setSecondPosition(this.currentValue[1]);
if (!this.secondDragging) {
if (this.currentValue[1] !== this.oldSecondValue) {
this.$emit('on-change', this.currentValue);
this.dispatch('FormItem', 'on-form-change', this.currentValue);
this.oldSecondValue = this.currentValue[1];
}
}
},
setSecondPosition (val) {
this.secondPosition = (val - this.min) / (this.max - this.min) * 100;
}
},
mounted () {
if (this.range) {
const isArray = Array.isArray(this.currentValue);
if (!isArray || (isArray && this.currentValue.length != 2) || (isArray && (isNaN(this.currentValue[0]) || isNaN(this.currentValue[1])))) {
this.currentValue = [this.min, this.max];
} else {
this.updateValue(this.currentValue, true);
}
} else {
if (typeof this.currentValue !== 'number') {
this.currentValue = this.min;
}
this.updateValue(this.currentValue);
}
} }
}; };
</script> </script>