element/packages/slider/src/main.vue

257 lines
6.9 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-08-11 07:51:13 +00:00
@keyup.native="onInputChange()"
ref="input"
2016-07-27 06:15:02 +00:00
:step="step"
:min="min"
:max="max"
size="small">
</el-input-number>
<div class="el-slider__runway"
:class="{ 'show-input': showInput }"
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="hovering = true"
@mouseleave="hovering = false"
@mousedown="onButtonDown"
:style="{left: currentPosition}" ref="button">
2016-07-27 06:15:02 +00:00
<div class="el-slider__button" :class="{ 'hover': hovering, 'dragging': dragging }"></div>
</div>
2016-08-11 07:51:13 +00:00
<transition name="popper-fade">
2016-09-18 14:01:26 +00:00
<div class="el-slider__pop" v-show="showTip" ref="pop">{{ value }}</div>
2016-08-11 07:51:13 +00:00
</transition>
2016-07-27 06:15:02 +00:00
<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-13 03:12:24 +00:00
import Popper from 'element-ui/src/utils/popper';
import ElInputNumber from 'element-ui/packages/input-number/index.js';
2016-07-27 06:15:02 +00:00
import { getStyle } from 'wind-dom/src/style';
2016-10-11 08:39:54 +00:00
import { addClass, removeClass } from 'wind-dom/src/class';
2016-07-27 06:15:02 +00:00
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
}
},
components: {
ElInputNumber
},
data() {
return {
2016-08-11 07:51:13 +00:00
inputValue: null,
timeout: null,
2016-07-27 06:15:02 +00:00
showTip: false,
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
popper: null,
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
showTip(val) {
if (val) {
this.$nextTick(() => {
this.updatePopper();
});
} else {
2016-08-11 07:51:13 +00:00
this.timeout = setTimeout(() => {
2016-07-27 06:15:02 +00:00
if (this.popper) {
this.popper.destroy();
this.popper = null;
}
2016-08-11 07:51:13 +00:00
}, 300);
2016-07-27 06:15:02 +00:00
}
},
value(val) {
this.$nextTick(() => {
this.updatePopper();
});
if (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: {
2016-08-11 07:51:13 +00:00
handlePopperStyle() {
let placementMap = { top: 'bottom', bottom: 'top' };
let placement = this.popper._popper.getAttribute('x-placement').split('-')[0];
let origin = placementMap[placement];
2016-10-11 08:39:54 +00:00
addClass(this.popper._popper, placement);
removeClass(this.popper._popper, placementMap[placement]);
2016-08-11 07:51:13 +00:00
this.popper._popper.style.transformOrigin = `center ${ origin }`;
},
2016-07-27 06:15:02 +00:00
updatePopper() {
if (this.popper) {
2016-08-11 07:51:13 +00:00
clearTimeout(this.timeout);
2016-07-27 06:15:02 +00:00
this.popper.update();
2016-08-11 07:51:13 +00:00
this.handlePopperStyle();
2016-07-27 06:15:02 +00:00
} else {
2016-08-11 07:51:13 +00:00
this.popper = new Popper(this.$refs.button, this.$refs.pop, { gpuAcceleration: false, placement: 'top' });
2016-07-27 06:15:02 +00:00
this.popper.onCreate(() => {
2016-08-11 07:51:13 +00:00
this.handlePopperStyle();
2016-07-27 06:15:02 +00:00
});
this.updatePopper();
}
},
setPosition(newPos) {
if (newPos >= 0 && (newPos <= 100)) {
var lengthPerStep = 100 / ((this.max - this.min) / this.step);
var steps = Math.round(newPos / lengthPerStep);
2016-08-11 07:51:13 +00:00
this.$emit('input', Math.round(steps * lengthPerStep * (this.max - this.min) * 0.01 + this.min));
2016-07-27 06:15:02 +00:00
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;
}
}
}
},
onSliderClick(event) {
var currentX = event.clientX;
var sliderOffsetLeft = this.$refs.slider.getBoundingClientRect().left;
2016-07-27 06:15:02 +00:00
var newPos = (currentX - sliderOffsetLeft) / this.$sliderWidth * 100;
this.setPosition(newPos);
},
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.currentX = event.clientX;
var diff = (this.currentX - this.startX) / this.$sliderWidth * 100;
this.newPos = this.startPos + diff;
this.setPosition(this.newPos);
}
},
onDragEnd() {
if (this.dragging) {
this.dragging = false;
this.setPosition(this.newPos);
window.removeEventListener('mousemove', this.onDragging);
window.removeEventListener('mouseup', this.onDragEnd);
}
},
onButtonDown(event) {
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
},
showTip() {
return this.dragging || this.hovering;
},
stops() {
let stopCount = (this.max - this.value) / this.step;
let result = [];
let currentLeft = parseFloat(this.currentPosition);
let stepWidth = 100 * this.step / (this.max - this.min);
for (let i = 1; i < stopCount; i++) {
result.push(currentLeft + i * stepWidth);
}
return result;
}
},
created() {
2016-10-19 06:53:32 +00:00
if (typeof this.value !== 'number' || 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-10-19 06:53:32 +00:00
this.$nextTick(() => {
this.inputValue = this.inputValue || this.value;
});
2016-07-27 06:15:02 +00:00
},
beforeDestroy() {
if (this.popper) {
this.popper.destroy();
}
}
};
</script>