element/packages/slider/src/main.vue

242 lines
6.5 KiB
Vue
Raw Normal View History

2016-07-27 06:15:02 +00:00
<template>
<div class="el-slider">
<el-input-number
2016-08-11 07:51:13 +00:00
v-model="inputValue"
2016-07-27 06:15:02 +00:00
v-if="showInput"
class="el-slider__input"
2016-10-21 06:56:14 +00:00
@keyup.native="onInputChange"
2016-08-11 07:51:13 +00:00
ref="input"
2016-07-27 06:15:02 +00:00
:step="step"
:disabled="disabled"
2016-07-27 06:15:02 +00:00
:min="min"
:max="max"
size="small">
</el-input-number>
<div class="el-slider__runway"
:class="{ 'show-input': showInput, 'disabled': disabled }"
2016-08-11 07:51:13 +00:00
@click="onSliderClick" ref="slider">
2016-07-27 06:15:02 +00:00
<div class="el-slider__bar" :style="{ width: currentPosition }"></div>
2016-10-19 06:53:32 +00:00
<div
class="el-slider__button-wrapper"
@mouseenter="handleMouseEnter"
@mouseleave="handleMouseLeave"
2016-10-19 06:53:32 +00:00
@mousedown="onButtonDown"
:class="{ 'hover': hovering, 'dragging': dragging }"
:style="{left: currentPosition}"
ref="button">
<el-tooltip placement="top" ref="tooltip">
<span slot="content">{{ value }}</span>
<div class="el-slider__button" :class="{ 'hover': hovering, 'dragging': dragging }"></div>
</el-tooltip>
2016-07-27 06:15:02 +00:00
</div>
<div class="el-slider__stop" v-for="item in stops" :style="{ 'left': item + '%' }" v-if="showStops"></div>
</div>
</div>
</template>
<script type="text/babel">
2016-10-25 13:35:41 +00:00
import ElInputNumber from 'element-ui/packages/input-number';
import ElTooltip from 'element-ui/packages/tooltip';
2016-07-27 06:15:02 +00:00
import { getStyle } from 'wind-dom/src/style';
export default {
name: 'ElSlider',
props: {
min: {
type: Number,
default: 0
},
max: {
type: Number,
default: 100
},
step: {
type: Number,
default: 1
},
defaultValue: {
type: Number,
default: 0
},
value: {
type: Number,
default: 0
},
showInput: {
type: Boolean,
default: false
},
showStops: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
2016-07-27 06:15:02 +00:00
}
},
components: {
ElInputNumber,
ElTooltip
2016-07-27 06:15:02 +00:00
},
data() {
return {
2016-11-30 02:57:13 +00:00
precision: 0,
2016-08-11 07:51:13 +00:00
inputValue: null,
timeout: null,
2016-07-27 06:15:02 +00:00
hovering: false,
dragging: false,
2016-10-19 06:53:32 +00:00
startX: 0,
currentX: 0,
startPos: 0,
2016-07-27 06:15:02 +00:00
newPos: null,
oldValue: this.value,
currentPosition: (this.value - this.min) / (this.max - this.min) * 100 + '%'
};
},
watch: {
2016-08-11 07:51:13 +00:00
inputValue(val) {
2016-09-09 06:27:49 +00:00
this.$emit('input', Number(val));
2016-08-11 07:51:13 +00:00
},
2016-07-27 06:15:02 +00:00
value(val) {
this.$nextTick(() => {
this.updatePopper();
});
2016-11-23 04:15:00 +00:00
if (typeof val !== 'number' || isNaN(val) || val < this.min) {
2016-08-11 07:51:13 +00:00
this.$emit('input', this.min);
2016-07-27 06:15:02 +00:00
return;
}
if (val > this.max) {
2016-08-11 07:51:13 +00:00
this.$emit('input', this.max);
2016-07-27 06:15:02 +00:00
return;
}
2016-08-11 07:51:13 +00:00
this.inputValue = val;
2016-07-27 06:15:02 +00:00
this.setPosition((val - this.min) * 100 / (this.max - this.min));
}
},
methods: {
handleMouseEnter() {
this.hovering = true;
this.$refs.tooltip.showPopper = true;
},
handleMouseLeave() {
this.hovering = false;
this.$refs.tooltip.showPopper = false;
2016-08-11 07:51:13 +00:00
},
2016-07-27 06:15:02 +00:00
updatePopper() {
this.$refs.tooltip.updatePopper();
2016-07-27 06:15:02 +00:00
},
setPosition(newPos) {
2016-11-30 08:58:53 +00:00
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);
let value = steps * lengthPerStep * (this.max - this.min) * 0.01 + this.min;
2016-11-30 02:57:13 +00:00
value = parseFloat(value.toFixed(this.precision));
2016-11-30 08:58:53 +00:00
this.$emit('input', value);
this.currentPosition = (this.value - this.min) / (this.max - this.min) * 100 + '%';
if (!this.dragging) {
if (this.value !== this.oldValue) {
this.$emit('change', this.value);
this.oldValue = this.value;
2016-07-27 06:15:02 +00:00
}
}
},
onSliderClick(event) {
if (this.disabled) return;
2016-11-21 07:11:29 +00:00
const sliderOffsetLeft = this.$refs.slider.getBoundingClientRect().left;
this.setPosition((event.clientX - sliderOffsetLeft) / this.$sliderWidth * 100);
2016-07-27 06:15:02 +00:00
},
onInputChange() {
if (this.value === '') {
return;
}
if (!isNaN(this.value)) {
this.setPosition((this.value - this.min) * 100 / (this.max - this.min));
}
2016-10-19 06:53:32 +00:00
},
onDragStart(event) {
this.dragging = true;
this.startX = event.clientX;
this.startPos = parseInt(this.currentPosition, 10);
},
onDragging(event) {
if (this.dragging) {
this.$refs.tooltip.showPopper = true;
2016-10-19 06:53:32 +00:00
this.currentX = event.clientX;
2016-11-21 07:11:29 +00:00
const diff = (this.currentX - this.startX) / this.$sliderWidth * 100;
2016-10-19 06:53:32 +00:00
this.newPos = this.startPos + diff;
this.setPosition(this.newPos);
}
},
onDragEnd() {
if (this.dragging) {
this.dragging = false;
this.$refs.tooltip.showPopper = false;
2016-10-19 06:53:32 +00:00
this.setPosition(this.newPos);
window.removeEventListener('mousemove', this.onDragging);
window.removeEventListener('mouseup', this.onDragEnd);
}
},
onButtonDown(event) {
if (this.disabled) return;
2016-10-19 06:53:32 +00:00
this.onDragStart(event);
window.addEventListener('mousemove', this.onDragging);
window.addEventListener('mouseup', this.onDragEnd);
2016-07-27 06:15:02 +00:00
}
},
computed: {
$sliderWidth() {
2016-08-11 07:51:13 +00:00
return parseInt(getStyle(this.$refs.slider, 'width'), 10);
2016-07-27 06:15:02 +00:00
},
stops() {
2016-11-21 07:11:29 +00:00
const stopCount = (this.max - this.value) / this.step;
const currentLeft = parseFloat(this.currentPosition);
const stepWidth = 100 * this.step / (this.max - this.min);
const result = [];
2016-07-27 06:15:02 +00:00
for (let i = 1; i < stopCount; i++) {
result.push(currentLeft + i * stepWidth);
}
return result;
}
},
created() {
2016-11-23 04:15:00 +00:00
if (typeof this.value !== 'number' ||
isNaN(this.value) ||
this.value < this.min) {
2016-08-11 07:51:13 +00:00
this.$emit('input', this.min);
2016-10-19 06:53:32 +00:00
} else if (this.value > this.max) {
this.$emit('input', this.max);
2016-07-27 06:15:02 +00:00
}
2016-11-30 02:57:13 +00:00
let precisions = [this.min, this.max, this.step].map(item => {
let decimal = ('' + item).split('.')[1];
return decimal ? decimal.length : 0;
});
this.precision = Math.max.apply(null, precisions);
this.inputValue = this.inputValue || this.value;
2016-07-27 06:15:02 +00:00
}
};
</script>