element/packages/slider/src/main.vue

388 lines
10 KiB
Vue
Raw Normal View History

2016-07-27 06:15:02 +00:00
<template>
2019-01-02 08:43:01 +00:00
<div
class="el-slider"
:class="{ 'is-vertical': vertical, 'el-slider--with-input': showInput }"
2019-01-02 08:43:01 +00:00
role="slider"
:aria-valuemin="min"
:aria-valuemax="max"
:aria-orientation="vertical ? 'vertical': 'horizontal'"
:aria-disabled="sliderDisabled"
>
2016-07-27 06:15:02 +00:00
<el-input-number
v-model="firstValue"
2017-02-17 11:09:59 +00:00
v-if="showInput && !range"
2016-07-27 06:15:02 +00:00
class="el-slider__input"
2016-08-11 07:51:13 +00:00
ref="input"
@change="$nextTick(emitChange)"
2016-07-27 06:15:02 +00:00
:step="step"
2018-01-29 09:54:38 +00:00
:disabled="sliderDisabled"
:controls="showInputControls"
2016-07-27 06:15:02 +00:00
:min="min"
:max="max"
2017-09-01 10:15:46 +00:00
:debounce="debounce"
2018-03-14 02:52:44 +00:00
:size="inputSize">
2016-07-27 06:15:02 +00:00
</el-input-number>
2019-01-02 08:43:01 +00:00
<div
class="el-slider__runway"
2018-01-29 09:54:38 +00:00
:class="{ 'show-input': showInput, 'disabled': sliderDisabled }"
2017-04-27 00:28:38 +00:00
:style="runwayStyle"
2017-02-17 11:09:59 +00:00
@click="onSliderClick"
ref="slider">
2016-10-19 06:53:32 +00:00
<div
2017-02-17 11:09:59 +00:00
class="el-slider__bar"
2017-04-27 00:28:38 +00:00
:style="barStyle">
2017-02-17 11:09:59 +00:00
</div>
<slider-button
2017-04-11 05:44:54 +00:00
:vertical="vertical"
2017-02-17 11:09:59 +00:00
v-model="firstValue"
2018-03-01 09:21:31 +00:00
:tooltip-class="tooltipClass"
2017-02-17 11:09:59 +00:00
ref="button1">
</slider-button>
<slider-button
2017-04-11 05:44:54 +00:00
:vertical="vertical"
2017-02-17 11:09:59 +00:00
v-model="secondValue"
2018-03-01 09:21:31 +00:00
:tooltip-class="tooltipClass"
2017-02-17 11:09:59 +00:00
ref="button2"
v-if="range">
</slider-button>
<div
class="el-slider__stop"
v-for="(item, key) in stops"
:key="key"
2017-04-11 05:44:54 +00:00
:style="vertical ? { 'bottom': item + '%' } : { 'left': item + '%' }"
2017-02-17 11:09:59 +00:00
v-if="showStops">
2016-07-27 06:15:02 +00:00
</div>
</div>
</div>
</template>
<script type="text/babel">
2016-10-25 13:35:41 +00:00
import ElInputNumber from 'element-ui/packages/input-number';
2017-02-17 11:09:59 +00:00
import SliderButton from './button.vue';
import Emitter from 'element-ui/src/mixins/emitter';
2016-07-27 06:15:02 +00:00
export default {
name: 'ElSlider',
mixins: [Emitter],
2018-01-29 09:54:38 +00:00
inject: {
elForm: {
default: ''
}
},
2016-07-27 06:15:02 +00:00
props: {
min: {
type: Number,
default: 0
},
max: {
type: Number,
default: 100
},
step: {
type: Number,
default: 1
},
value: {
2017-02-17 11:09:59 +00:00
type: [Number, Array],
2016-07-27 06:15:02 +00:00
default: 0
},
showInput: {
type: Boolean,
default: false
},
showInputControls: {
type: Boolean,
default: true
},
2018-03-14 02:52:44 +00:00
inputSize: {
type: String,
default: 'small'
},
2016-07-27 06:15:02 +00:00
showStops: {
type: Boolean,
default: false
},
2017-03-10 14:24:04 +00:00
showTooltip: {
type: Boolean,
default: true
},
formatTooltip: Function,
disabled: {
type: Boolean,
default: false
2017-02-17 11:09:59 +00:00
},
range: {
type: Boolean,
default: false
2017-04-11 05:44:54 +00:00
},
vertical: {
type: Boolean,
default: false
},
2017-04-27 00:28:38 +00:00
height: {
2017-04-11 05:44:54 +00:00
type: String
2017-09-01 10:15:46 +00:00
},
debounce: {
type: Number,
default: 300
},
label: {
type: String
2018-03-01 09:21:31 +00:00
},
tooltipClass: String
2016-07-27 06:15:02 +00:00
},
components: {
ElInputNumber,
2017-02-17 11:09:59 +00:00
SliderButton
2016-07-27 06:15:02 +00:00
},
data() {
return {
2017-02-17 11:09:59 +00:00
firstValue: null,
secondValue: null,
oldValue: null,
2017-08-03 06:08:08 +00:00
dragging: false,
sliderSize: 1
2016-07-27 06:15:02 +00:00
};
},
watch: {
2017-02-17 11:09:59 +00:00
value(val, oldVal) {
if (this.dragging ||
Array.isArray(val) &&
Array.isArray(oldVal) &&
val.every((item, index) => item === oldVal[index])) {
2016-07-27 06:15:02 +00:00
return;
}
2017-02-17 11:09:59 +00:00
this.setValues();
2016-08-11 07:51:13 +00:00
},
2017-02-17 11:09:59 +00:00
dragging(val) {
if (!val) {
this.setValues();
}
2016-07-27 06:15:02 +00:00
},
2017-02-17 11:09:59 +00:00
firstValue(val) {
if (this.range) {
this.$emit('input', [this.minValue, this.maxValue]);
} else {
this.$emit('input', val);
2016-11-30 08:58:53 +00:00
}
2017-02-17 11:09:59 +00:00
},
2016-11-30 08:58:53 +00:00
2017-02-17 11:09:59 +00:00
secondValue() {
if (this.range) {
this.$emit('input', [this.minValue, this.maxValue]);
2016-07-27 06:15:02 +00:00
}
},
2017-02-17 11:09:59 +00:00
min() {
this.setValues();
2016-07-27 06:15:02 +00:00
},
2017-02-17 11:09:59 +00:00
max() {
this.setValues();
}
},
2016-10-19 06:53:32 +00:00
2017-02-17 11:09:59 +00:00
methods: {
valueChanged() {
if (this.range) {
return ![this.minValue, this.maxValue]
.every((item, index) => item === this.oldValue[index]);
} else {
return this.value !== this.oldValue;
}
2016-10-19 06:53:32 +00:00
},
2017-02-17 11:09:59 +00:00
setValues() {
if (this.min > this.max) {
console.error('[Element Error][Slider]min should not be greater than max.');
return;
}
2017-02-17 11:09:59 +00:00
const val = this.value;
if (this.range && Array.isArray(val)) {
if (val[1] < this.min) {
this.$emit('input', [this.min, this.min]);
} else if (val[0] > this.max) {
this.$emit('input', [this.max, this.max]);
} else if (val[0] < this.min) {
this.$emit('input', [this.min, val[1]]);
} else if (val[1] > this.max) {
this.$emit('input', [val[0], this.max]);
} else {
this.firstValue = val[0];
this.secondValue = val[1];
if (this.valueChanged()) {
this.dispatch('ElFormItem', 'el.form.change', [this.minValue, this.maxValue]);
2017-02-17 11:09:59 +00:00
this.oldValue = val.slice();
}
}
} else if (!this.range && typeof val === 'number' && !isNaN(val)) {
if (val < this.min) {
this.$emit('input', this.min);
} else if (val > this.max) {
this.$emit('input', this.max);
} else {
this.firstValue = val;
if (this.valueChanged()) {
this.dispatch('ElFormItem', 'el.form.change', val);
2017-02-17 11:09:59 +00:00
this.oldValue = val;
}
}
2016-10-19 06:53:32 +00:00
}
},
2017-02-17 11:09:59 +00:00
setPosition(percent) {
const targetValue = this.min + percent * (this.max - this.min) / 100;
if (!this.range) {
this.$refs.button1.setPosition(percent);
return;
2016-10-19 06:53:32 +00:00
}
2017-02-17 11:09:59 +00:00
let button;
if (Math.abs(this.minValue - targetValue) < Math.abs(this.maxValue - targetValue)) {
button = this.firstValue < this.secondValue ? 'button1' : 'button2';
} else {
button = this.firstValue > this.secondValue ? 'button1' : 'button2';
}
this.$refs[button].setPosition(percent);
2016-10-19 06:53:32 +00:00
},
2017-02-17 11:09:59 +00:00
onSliderClick(event) {
2018-01-29 09:54:38 +00:00
if (this.sliderDisabled || this.dragging) return;
2017-08-20 14:07:03 +00:00
this.resetSize();
2017-04-11 05:44:54 +00:00
if (this.vertical) {
const sliderOffsetBottom = this.$refs.slider.getBoundingClientRect().bottom;
2017-08-03 06:08:08 +00:00
this.setPosition((sliderOffsetBottom - event.clientY) / this.sliderSize * 100);
2017-04-11 05:44:54 +00:00
} else {
const sliderOffsetLeft = this.$refs.slider.getBoundingClientRect().left;
2017-08-03 06:08:08 +00:00
this.setPosition((event.clientX - sliderOffsetLeft) / this.sliderSize * 100);
}
this.emitChange();
2017-08-03 06:08:08 +00:00
},
resetSize() {
if (this.$refs.slider) {
this.sliderSize = this.$refs.slider[`client${ this.vertical ? 'Height' : 'Width' }`];
2017-04-11 05:44:54 +00:00
}
},
emitChange() {
this.$nextTick(() => {
this.$emit('change', this.range ? [this.minValue, this.maxValue] : this.value);
});
2016-07-27 06:15:02 +00:00
}
},
computed: {
stops() {
if (!this.showStops || this.min > this.max) return [];
2017-06-18 09:48:18 +00:00
if (this.step === 0) {
process.env.NODE_ENV !== 'production' &&
console.warn('[Element Warn][Slider]step should not be 0.');
return [];
}
2017-02-17 11:09:59 +00:00
const stopCount = (this.max - this.min) / this.step;
2016-11-21 07:11:29 +00:00
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++) {
2017-02-17 11:09:59 +00:00
result.push(i * stepWidth);
2016-07-27 06:15:02 +00:00
}
2017-02-17 11:09:59 +00:00
if (this.range) {
return result.filter(step => {
return step < 100 * (this.minValue - this.min) / (this.max - this.min) ||
step > 100 * (this.maxValue - this.min) / (this.max - this.min);
});
} else {
return result.filter(step => step > 100 * (this.firstValue - this.min) / (this.max - this.min));
}
},
minValue() {
return Math.min(this.firstValue, this.secondValue);
},
maxValue() {
return Math.max(this.firstValue, this.secondValue);
},
2017-04-11 05:44:54 +00:00
barSize() {
2017-02-17 11:09:59 +00:00
return this.range
? `${ 100 * (this.maxValue - this.minValue) / (this.max - this.min) }%`
: `${ 100 * (this.firstValue - this.min) / (this.max - this.min) }%`;
},
2017-04-11 05:44:54 +00:00
barStart() {
2017-02-17 11:09:59 +00:00
return this.range
? `${ 100 * (this.minValue - this.min) / (this.max - this.min) }%`
: '0%';
},
precision() {
let precisions = [this.min, this.max, this.step].map(item => {
let decimal = ('' + item).split('.')[1];
return decimal ? decimal.length : 0;
});
return Math.max.apply(null, precisions);
2017-04-27 00:28:38 +00:00
},
runwayStyle() {
return this.vertical ? { height: this.height } : {};
},
barStyle() {
return this.vertical
? {
height: this.barSize,
bottom: this.barStart
} : {
width: this.barSize,
left: this.barStart
};
2018-01-29 09:54:38 +00:00
},
sliderDisabled() {
return this.disabled || (this.elForm || {}).disabled;
2016-07-27 06:15:02 +00:00
}
},
2017-02-17 11:09:59 +00:00
mounted() {
let valuetext;
2017-02-17 11:09:59 +00:00
if (this.range) {
if (Array.isArray(this.value)) {
this.firstValue = Math.max(this.min, this.value[0]);
this.secondValue = Math.min(this.max, this.value[1]);
} else {
this.firstValue = this.min;
this.secondValue = this.max;
}
this.oldValue = [this.firstValue, this.secondValue];
valuetext = `${this.firstValue}-${this.secondValue}`;
2017-02-17 11:09:59 +00:00
} else {
if (typeof this.value !== 'number' || isNaN(this.value)) {
this.firstValue = this.min;
} else {
this.firstValue = Math.min(this.max, Math.max(this.min, this.value));
}
this.oldValue = this.firstValue;
valuetext = this.firstValue;
2016-07-27 06:15:02 +00:00
}
this.$el.setAttribute('aria-valuetext', valuetext);
// label screen reader
this.$el.setAttribute('aria-label', this.label ? this.label : `slider between ${this.min} and ${this.max}`);
2017-08-03 06:08:08 +00:00
this.resetSize();
window.addEventListener('resize', this.resetSize);
},
beforeDestroy() {
window.removeEventListener('resize', this.resetSize);
2016-07-27 06:15:02 +00:00
}
};
</script>