【Vue】Element滑块Slider自定义提示Tooltip

8,864 阅读1分钟

分析

客户要求值要始终显示,但Element滑块用的是自身的Tooltip组件。

其源码如下:

  <!-- 省略了一些属性:<div ...> -->
  <div>
    <el-tooltip
      placement="top"
      ref="tooltip"
      :popper-class="tooltipClass"
      :disabled="!showTooltip">
      <span slot="content">{{ formatValue }}</span>
      <div
        class="el-slider__button"
        :class="{ 'hover': hovering, 'dragging': dragging }"></div>
    </el-tooltip>
  </div>

Tooltip的触发机制是鼠标事件,只有鼠标移动到对应的元素上时才创建Tooltip,该行为不符合客户需求。

Element文档中描述,可以通过show-tooltip来禁用默认的Tooltip,并可以通过input事件来实时同步改变的数据。

同时通过页面审查元素,发现滑动点是通过left属性完成位移的,同时通过translateX来完成元素向左偏移一半。

如代码所示:

<style>
  .el-slider__button-wrapper {
    /** ... */
    ransform: translateX(-50%);
  }
</style>
<div
  tabindex="0"
  class="el-slider__button-wrapper"
  style="left: 45%;">
  <!-- ... -->
</div>

组件化

我们可以基于分析的几点来实现自定义的Tooltip。定义一个MySlider.vue组件:

<template>
  <div class="my-slider">
    <div class="my-slider__tooltip" :style="style">
      <el-button
        class="my-slider__tooltip-wrapper"
        size="mini"
      >
        {{ slider }}
      </el-button>
    </div>
    <el-slider
      v-model="slider"
      :format-tooltip="(value) => `${value}${unit}`"
      :show-tooltip="false"
      :min="min"
      :max="max"
      @input="input"
    ></el-slider>
  </div>
</template>

<script>
export default {
  name: 'MySlider',
  model: {
    prop: 'value',
    event: 'change',
  },
  props: {
    value: {
      type: Number,
      default: 100,
    },
    min: {
      type: Number,
      default: 0,
    },
    max: {
      type: Number,
      default: 100,
    },
  },
  data() {
    return {
      slider: this.value,
    }
  },
  watch: {
    value(newValue) {
      this.slider = newValue
    },
  },
  computed: {
    style() {
      const length = this.max - this.min,
        progress = this.slider - this.min,
        left = progress / length * 100
      return {
        paddingLeft: `${left}%`,
      }
    },
  },
  methods: {
    input(value) {
      this.$emit('change', value)
    },
  },
}
</script>

<style lang="scss" scoped>
.my-slider {
  .my-slider__tooltip {
    text-align: left;
    .my-slider__tooltip-wrapper {
      height: 32px;
      transform: translateX(-50%);
      top: -50%;
    }
  }
}
</style>

引入并使用它:

<template>
    <my-slider v-model="luminosity"></my-slider>
</template>
<script>
import MySlider from '@/components/MySlider'

export default {
  name: 'MyController',
  components: {
    MySlider,
  },
  data() {
    return {
      luminosity: 50,
    }
  },
}
</script>