Jelajahi Sumber

Slider: add disabled/use tooltip (#589)

杨奕 8 tahun lalu
induk
melakukan
e51d753ffd

+ 1 - 1
CHANGELOG.md

@@ -19,7 +19,7 @@
 - 修复 Input Number min max 属性设置后点击加减出现的崩溃的bug
 - 优化 TimePicker/DatePicker 输入日期行为
 - 修复 DatePicker 输入禁用状态的日期却生效的问题 #484
-
+- 新增 Slider 的 disabled 属性
 
 #### 非兼容性更新
 

+ 11 - 5
examples/docs/zh-cn/slider.md

@@ -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 |

+ 31 - 56
packages/slider/src/main.vue

@@ -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>

+ 2 - 1
packages/theme-default/src/common/var.css

@@ -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
     --------------------------*/

+ 57 - 44
packages/theme-default/src/slider.css

@@ -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;
+        background-color: var(--slider-button-hover-color);
       }
-    }
 
-    @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;
-      }
-
-      &::after {
-        triangle: 9px bottom var(--slider-main-background-color);
-        position: absolute;
-        bottom: -14px;
-        left: 4px;
-      }
-
-      &.top::after {
-        content: '';
+      &:hover,
+      &.hover {
+        cursor: grab;
       }
 
-      &.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;
-    }
   }
 }

+ 31 - 11
test/unit/specs/slider.spec.js

@@ -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: `