mirror of https://github.com/ElemeFE/element
Slider: add disabled/use tooltip (#589)
parent
588523e808
commit
e51d753ffd
|
@ -19,7 +19,7 @@
|
|||
- 修复 Input Number min max 属性设置后点击加减出现的崩溃的bug
|
||||
- 优化 TimePicker/DatePicker 输入日期行为
|
||||
- 修复 DatePicker 输入禁用状态的日期却生效的问题 #484
|
||||
|
||||
- 新增 Slider 的 disabled 属性
|
||||
|
||||
#### 非兼容性更新
|
||||
|
||||
|
|
|
@ -4,9 +4,10 @@
|
|||
return {
|
||||
value1: 0,
|
||||
value2: 50,
|
||||
value3: 0,
|
||||
value3: 42,
|
||||
value4: 0,
|
||||
value5: 0
|
||||
value5: 0,
|
||||
value6: 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -58,6 +59,10 @@
|
|||
<span class="demonstration">自定义初始值</span>
|
||||
<el-slider v-model="value2"></el-slider>
|
||||
</div>
|
||||
<div class="block">
|
||||
<span class="demonstration">禁用</span>
|
||||
<el-slider v-model="value3" disabled></el-slider>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -83,14 +88,14 @@
|
|||
<div class="block">
|
||||
<span class="demonstration">不显示间断点</span>
|
||||
<el-slider
|
||||
v-model="value3"
|
||||
v-model="value4"
|
||||
:step="10">
|
||||
</el-slider>
|
||||
</div>
|
||||
<div class="block">
|
||||
<span class="demonstration">显示间断点</span>
|
||||
<el-slider
|
||||
v-model="value4"
|
||||
v-model="value5"
|
||||
:step="10"
|
||||
show-stops>
|
||||
</el-slider>
|
||||
|
@ -119,7 +124,7 @@
|
|||
<template>
|
||||
<div class="block">
|
||||
<el-slider
|
||||
v-model="value5"
|
||||
v-model="value6"
|
||||
show-input>
|
||||
</el-slider>
|
||||
</div>
|
||||
|
@ -142,6 +147,7 @@
|
|||
|---------- |-------------- |---------- |-------------------------------- |-------- |
|
||||
| min | 最小值 | number | — | 0 |
|
||||
| max | 最大值 | number | — | 100 |
|
||||
| disabled | 是否禁用 | boolean | — | false |
|
||||
| step | 步长 | number | — | 1 |
|
||||
| show-input | 是否显示输入框 | boolean | — | false |
|
||||
| show-stops | 是否显示间断点 | boolean | — | false |
|
||||
|
|
|
@ -7,35 +7,37 @@
|
|||
@keyup.native="onInputChange"
|
||||
ref="input"
|
||||
:step="step"
|
||||
:disabled="disabled"
|
||||
:min="min"
|
||||
:max="max"
|
||||
size="small">
|
||||
</el-input-number>
|
||||
<div class="el-slider__runway"
|
||||
:class="{ 'show-input': showInput }"
|
||||
:class="{ 'show-input': showInput, 'disabled': disabled }"
|
||||
@click="onSliderClick" ref="slider">
|
||||
<div class="el-slider__bar" :style="{ width: currentPosition }"></div>
|
||||
<div
|
||||
class="el-slider__button-wrapper"
|
||||
@mouseenter="hovering = true"
|
||||
@mouseleave="hovering = false"
|
||||
@mouseenter="handleMouseEnter"
|
||||
@mouseleave="handleMouseLeave"
|
||||
@mousedown="onButtonDown"
|
||||
:style="{left: currentPosition}" ref="button">
|
||||
<div class="el-slider__button" :class="{ 'hover': hovering, 'dragging': dragging }"></div>
|
||||
: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>
|
||||
</div>
|
||||
<transition name="popper-fade">
|
||||
<div class="el-slider__pop" v-show="showTip" ref="pop">{{ value }}</div>
|
||||
</transition>
|
||||
<div class="el-slider__stop" v-for="item in stops" :style="{ 'left': item + '%' }" v-if="showStops"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script type="text/babel">
|
||||
import Popper from 'element-ui/src/utils/popper';
|
||||
import ElInputNumber from 'element-ui/packages/input-number/index.js';
|
||||
import ElTooltip from 'element-ui/packages/tooltip/index.js';
|
||||
import { getStyle } from 'wind-dom/src/style';
|
||||
import { addClass, removeClass } from 'wind-dom/src/class';
|
||||
|
||||
export default {
|
||||
name: 'ElSlider',
|
||||
|
@ -68,24 +70,27 @@
|
|||
showStops: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
ElInputNumber
|
||||
ElInputNumber,
|
||||
ElTooltip
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
inputValue: null,
|
||||
timeout: null,
|
||||
showTip: false,
|
||||
hovering: false,
|
||||
dragging: false,
|
||||
startX: 0,
|
||||
currentX: 0,
|
||||
startPos: 0,
|
||||
popper: null,
|
||||
newPos: null,
|
||||
oldValue: this.value,
|
||||
currentPosition: (this.value - this.min) / (this.max - this.min) * 100 + '%'
|
||||
|
@ -97,21 +102,6 @@
|
|||
this.$emit('input', Number(val));
|
||||
},
|
||||
|
||||
showTip(val) {
|
||||
if (val) {
|
||||
this.$nextTick(() => {
|
||||
this.updatePopper();
|
||||
});
|
||||
} else {
|
||||
this.timeout = setTimeout(() => {
|
||||
if (this.popper) {
|
||||
this.popper.destroy();
|
||||
this.popper = null;
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
},
|
||||
|
||||
value(val) {
|
||||
this.$nextTick(() => {
|
||||
this.updatePopper();
|
||||
|
@ -130,27 +120,18 @@
|
|||
},
|
||||
|
||||
methods: {
|
||||
handlePopperStyle() {
|
||||
let placementMap = { top: 'bottom', bottom: 'top' };
|
||||
let placement = this.popper._popper.getAttribute('x-placement').split('-')[0];
|
||||
let origin = placementMap[placement];
|
||||
addClass(this.popper._popper, placement);
|
||||
removeClass(this.popper._popper, placementMap[placement]);
|
||||
this.popper._popper.style.transformOrigin = `center ${ origin }`;
|
||||
handleMouseEnter() {
|
||||
this.hovering = true;
|
||||
this.$refs.tooltip.showPopper = true;
|
||||
},
|
||||
|
||||
handleMouseLeave() {
|
||||
this.hovering = false;
|
||||
this.$refs.tooltip.showPopper = false;
|
||||
},
|
||||
|
||||
updatePopper() {
|
||||
if (this.popper) {
|
||||
clearTimeout(this.timeout);
|
||||
this.popper.update();
|
||||
this.handlePopperStyle();
|
||||
} else {
|
||||
this.popper = new Popper(this.$refs.button, this.$refs.pop, { gpuAcceleration: false, placement: 'top' });
|
||||
this.popper.onCreate(() => {
|
||||
this.handlePopperStyle();
|
||||
});
|
||||
this.updatePopper();
|
||||
}
|
||||
this.$refs.tooltip.updatePopper();
|
||||
},
|
||||
|
||||
setPosition(newPos) {
|
||||
|
@ -169,6 +150,7 @@
|
|||
},
|
||||
|
||||
onSliderClick(event) {
|
||||
if (this.disabled) return;
|
||||
var currentX = event.clientX;
|
||||
var sliderOffsetLeft = this.$refs.slider.getBoundingClientRect().left;
|
||||
var newPos = (currentX - sliderOffsetLeft) / this.$sliderWidth * 100;
|
||||
|
@ -192,6 +174,7 @@
|
|||
|
||||
onDragging(event) {
|
||||
if (this.dragging) {
|
||||
this.$refs.tooltip.showPopper = true;
|
||||
this.currentX = event.clientX;
|
||||
var diff = (this.currentX - this.startX) / this.$sliderWidth * 100;
|
||||
this.newPos = this.startPos + diff;
|
||||
|
@ -202,6 +185,7 @@
|
|||
onDragEnd() {
|
||||
if (this.dragging) {
|
||||
this.dragging = false;
|
||||
this.$refs.tooltip.showPopper = false;
|
||||
this.setPosition(this.newPos);
|
||||
window.removeEventListener('mousemove', this.onDragging);
|
||||
window.removeEventListener('mouseup', this.onDragEnd);
|
||||
|
@ -209,6 +193,7 @@
|
|||
},
|
||||
|
||||
onButtonDown(event) {
|
||||
if (this.disabled) return;
|
||||
this.onDragStart(event);
|
||||
window.addEventListener('mousemove', this.onDragging);
|
||||
window.addEventListener('mouseup', this.onDragEnd);
|
||||
|
@ -220,10 +205,6 @@
|
|||
return parseInt(getStyle(this.$refs.slider, 'width'), 10);
|
||||
},
|
||||
|
||||
showTip() {
|
||||
return this.dragging || this.hovering;
|
||||
},
|
||||
|
||||
stops() {
|
||||
let stopCount = (this.max - this.value) / this.step;
|
||||
let result = [];
|
||||
|
@ -245,12 +226,6 @@
|
|||
this.$nextTick(() => {
|
||||
this.inputValue = this.inputValue || this.value;
|
||||
});
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
if (this.popper) {
|
||||
this.popper.destroy();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -377,8 +377,9 @@
|
|||
--------------------------*/
|
||||
--slider-main-background-color: var(--color-primary);
|
||||
--slider-runway-background-color: #e5e9f2;
|
||||
--slider-runway-hover-color: #1d8ce0;
|
||||
--slider-button-hover-color: #1d8ce0;
|
||||
--slider-stop-background-color: #c0ccda;
|
||||
--slider-disable-color: #c0ccda;
|
||||
|
||||
/*Steps
|
||||
--------------------------*/
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
@charset "UTF-8";
|
||||
@import "./input-number.css";
|
||||
@import "./tooltip.css";
|
||||
@import "./common/var.css";
|
||||
|
||||
@component-namespace el {
|
||||
|
@ -19,6 +20,42 @@
|
|||
margin-right: 160px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
cursor: default;
|
||||
|
||||
.el-slider__bar, .el-slider__button {
|
||||
background-color: var(--slider-disable-color);
|
||||
}
|
||||
|
||||
.el-slider__button-wrapper {
|
||||
&:hover,
|
||||
&.hover {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
&.dragging {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.el-slider__button {
|
||||
&:hover,
|
||||
&.hover,
|
||||
&.dragging {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&.hover {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
&.dragging {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@e input {
|
||||
|
@ -41,60 +78,42 @@
|
|||
top: -16px;
|
||||
transform: translateX(-50%);
|
||||
background-color: transparent;
|
||||
text-align: center;
|
||||
|
||||
.el-tooltip {
|
||||
margin-top: 9px;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&.hover {
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
&.dragging {
|
||||
cursor: grabbing;
|
||||
}
|
||||
}
|
||||
|
||||
@e button {
|
||||
size: 12px;
|
||||
background-color: var(--slider-main-background-color);
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
left: 12px;
|
||||
cursor: pointer;
|
||||
transition: .2s;
|
||||
|
||||
&:hover,
|
||||
&.hover,
|
||||
&.dragging {
|
||||
transform: scale(1.5);
|
||||
background-color: #1d8ce0;
|
||||
}
|
||||
}
|
||||
|
||||
@e pop {
|
||||
@utils-user-select none;
|
||||
font-size: 12px;
|
||||
line-height: 26px;
|
||||
text-align: center;
|
||||
size: 26px;
|
||||
border-radius: 50%;
|
||||
background-color: var(--slider-main-background-color);
|
||||
color: #fff;
|
||||
cursor: default;
|
||||
z-index: var(--index-top);
|
||||
transition: transform .3s, opacity .3s;
|
||||
transform-origin: center bottom;
|
||||
|
||||
&::before {
|
||||
triangle: 9px top var(--slider-main-background-color);
|
||||
position: absolute;
|
||||
top: -14px;
|
||||
left: 4px;
|
||||
background-color: var(--slider-button-hover-color);
|
||||
}
|
||||
|
||||
&::after {
|
||||
triangle: 9px bottom var(--slider-main-background-color);
|
||||
position: absolute;
|
||||
bottom: -14px;
|
||||
left: 4px;
|
||||
&:hover,
|
||||
&.hover {
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
&.top::after {
|
||||
content: '';
|
||||
}
|
||||
|
||||
&.bottom::before {
|
||||
content: '';
|
||||
&.dragging {
|
||||
cursor: grabbing;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,11 +124,5 @@
|
|||
background-color: var(--slider-stop-background-color);
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.popper-fade-enter,
|
||||
.popper-fade-leave-active {
|
||||
transform: scale(0.1);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,7 @@ import Slider from 'packages/slider';
|
|||
describe('Slider', () => {
|
||||
it('create', () => {
|
||||
const vm = createTest(Slider);
|
||||
const popup = vm.$el.querySelector('.el-slider__pop');
|
||||
expect(popup.textContent).to.equal('0');
|
||||
expect(vm.value).to.equal(0);
|
||||
});
|
||||
|
||||
it('should not exceed min and max', done => {
|
||||
|
@ -36,7 +35,7 @@ describe('Slider', () => {
|
|||
}, 100);
|
||||
});
|
||||
|
||||
it('show tooltip', done => {
|
||||
it('show tooltip', () => {
|
||||
const vm = createVue({
|
||||
template: `
|
||||
<div>
|
||||
|
@ -52,14 +51,10 @@ describe('Slider', () => {
|
|||
}
|
||||
}, true);
|
||||
const slider = vm.$children[0];
|
||||
const popup = vm.$el.querySelector('.el-slider__pop');
|
||||
slider.onDragStart({ clientX: 0 });
|
||||
vm.$nextTick(() => {
|
||||
expect(popup.style.display).to.not.equal('none');
|
||||
slider.onDragEnd();
|
||||
expect(slider.showTip).to.false;
|
||||
done();
|
||||
});
|
||||
slider.handleMouseEnter();
|
||||
expect(slider.$refs.tooltip.showPopper).to.true;
|
||||
slider.handleMouseLeave();
|
||||
expect(slider.$refs.tooltip.showPopper).to.false;
|
||||
});
|
||||
|
||||
it('drag', done => {
|
||||
|
@ -110,6 +105,31 @@ describe('Slider', () => {
|
|||
}, 150);
|
||||
});
|
||||
|
||||
it('disabled', done => {
|
||||
const vm = createVue({
|
||||
template: `
|
||||
<div>
|
||||
<el-slider v-model="value" disabled></el-slider>
|
||||
</div>
|
||||
`,
|
||||
|
||||
data() {
|
||||
return {
|
||||
value: 0
|
||||
};
|
||||
}
|
||||
}, true);
|
||||
const slider = vm.$children[0];
|
||||
setTimeout(() => {
|
||||
slider.onButtonDown({ clientX: 0 });
|
||||
slider.onDragging({ clientX: 100 });
|
||||
slider.onDragEnd();
|
||||
slider.onSliderClick({ clientX: 200 });
|
||||
expect(vm.value).to.equal(0);
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('show input', done => {
|
||||
const vm = createVue({
|
||||
template: `
|
||||
|
|
Loading…
Reference in New Issue