Vue2滑动输入条(Slider)

简介: 这是一个基于 Vue3 的滑动输入条(Slider)组件,提供了丰富的自定义选项,如最小值、最大值、初始值、宽度、禁用状态及双滑块模式等。用户可通过拖动滑块或点击输入条调整数值。代码示例展示了如何创建组件及在页面中引入使用。包含单滑块与双滑块模式的效果图。

组件支持自定义设置:

  • 滑动输入条最小值(min),默认0
  • 滑动输入条最大值(max),默认100
  • 滑动输入条初始默认值(initialValue),当 range 为 false 时,使用 number,否则用 [number, number],在未设置value(v-model)时生效,默认[0, 100]
  • 滑动输入条在页面中的宽度(width),默认600px
  • 是否禁用(disabled),默认false
  • 是否双滑块模式(range),默认false
  • (v-model)设置当前取值(value),当 range 为 false 时,使用 number,否则用 [number, number]

可以通过鼠标拖动滑块来调整最大最小值,或者直接点击输入条上某个位置,直接切换数值

效果图如下:

单滑块模式(:range="false"):

双滑块模式(:range="true"):

①创建滑动输入条组件Slider.vue

<template>
  <div :class="['m-slider', { disabled: disabled }]" ref="slider" :style="`width: ${width}px;`">
    <div class="u-slider-rail" @click.self="onClickPoint"></div>
    <div class="u-slider-track" :class="{trackTransition: transition}" :style="`left: ${left}px; right: auto; width: ${right - left}px;`"></div>
    <div class="u-slider-handle" :class="{handleTransition: transition}" v-if="range" tabindex="0" ref="left" @mousedown="onLeftMouseDown" :style="`left: ${left}px; right: auto; transform: translateX(-50%);`"></div>
    <div class="u-slider-handle" :class="{handleTransition: transition}" tabindex="0" ref="right" @mousedown="onRightMouseDown" :style="`left: ${right}px; right: auto; transform: translateX(-50%);`"></div>
  </div>
</template>
<script>
export default {
  name: 'Slider',
  model: {
    prop: 'value',
    event: 'change'
  },
  props: {
    min: { // 滑动输入条最小值
      type: Number,
      default: 0
    },
    max: { // 滑动输入条最大值
      type: Number,
      default: 100
    },
    initialValue: { // 滑动输入条初始默认值,当 range 为 false 时,使用 number,否则用 [number, number],在未设置value(v-model)时生效
      type: [Number, Array],
      default: () => {
        return [0, 100]
      }
    },
    width: { // 滑动输入条在页面中的宽度
      type: Number,
      default: 600
    },
    disabled: { // 是否禁用
      type: Boolean,
      default: false
    },
    range: { // 是否双滑块模式
      type: Boolean,
      default: false
    },
    value: { // (v-model)设置当前取值,当 range 为 false 时,使用 number,否则用 [number, number]
      type: [Number, Array],
      default: null
    }
  },
  data () {
    return {
      transition: false,
      timer: null,
      left: 0, // 左滑块距离滑动条左端的距离
      right: 0 // 右滑动距离滑动条左端的距离
    }
  },
  computed: {
    scale () {
      return this.width / (this.max - this.min)
    },
    sliderValue () {
      const high = Math.round(this.right / this.scale + this.min)
      if (this.range) {
        const low = Math.round(this.left / this.scale + this.min)
        return [low, high]
      }
      return high
    }
  },
  watch: {
    sliderValue (to) {
      this.$emit('change', to) // 通知v-model值变化
    }
  },
  created () {
    if (this.range) { // 双滑块模式
      const leftVal = (this.value && (this.value[0] === 0 || this.value[0])) ? this.value[0] : this.initialValue[0]
      this.left = (leftVal - this.min) * this.scale
      const rightVal = (this.value && (this.value[1] === 0 || this.value[1])) ? this.value[1] : this.initialValue[1]
      this.right = (rightVal - this.min) * this.scale
    } else {
      const rightVal = this.value ? this.value : (Array.isArray(this.initialValue) ? 100 : this.initialValue)
      this.right = (rightVal - this.min) * this.scale
    }
  },
  methods: {
    onClickPoint (e) { // 点击滑动条,移动滑块
      if (this.transition) {
        clearTimeout(this.timer)
        this.timer = null
      } else {
        this.transition = true
      }
      this.timer = setTimeout(() => {
        this.transition = false
      }, 300)
      // 元素是absolute时,e.layerX是相对于自身元素左上角的水平位置
      var moveX = e.layerX // 鼠标点击位置距离滑动输入条左端的水平距离
      if (this.range) { // 双滑块模式
        if (moveX <= this.left) {
          this.left = moveX
        } else if (moveX >= this.right) {
          this.right = moveX
        } else {
          if ((moveX - this.left) < (this.right - moveX)) {
            this.left = moveX
          } else {
            this.right = moveX
          }
        }
      } else { // 单滑块模式
        this.right = moveX
      }
    },
    onLeftMouseDown () { // 在滚动条上拖动左滑块
      const leftX = this.$refs.slider.getBoundingClientRect().left // 滑动条左端距离屏幕可视区域左边界的距离
      document.onmousemove = (e) => {
        // e.clientX返回事件被触发时鼠标指针相对于浏览器可视窗口的水平坐标
        var moveX = e.clientX - leftX
        if (moveX < 0) {
          this.left = 0
        } else if (moveX >= 0 && moveX <= this.right) {
          this.left = moveX
        } else { // moveX > this.right
          this.left = this.right
          this.onRightMouseDown()
        }
      }
      document.onmouseup = () => {
        document.onmousemove = null
      }
    },
    onRightMouseDown () { // 在滚动条上拖动右滑块
      const leftX = this.$refs.slider.getBoundingClientRect().left // 滑动条左端距离屏幕可视区域左边界的距离
      document.onmousemove = (e) => {
        // e.clientX返回事件被触发时鼠标指针相对于浏览器可视窗口的水平坐标
        console.log(e.clientX)
        var moveX = e.clientX - leftX
        if (moveX > this.width) {
          this.right = this.width
        } else if (this.left <= moveX && moveX <= this.width) {
          this.right = moveX
        } else { // moveX < this.left
          this.right = this.left
          this.onLeftMouseDown()
        }
      }
      document.onmouseup = () => {
        document.onmousemove = null
      }
    }
  }
}
</script>
<style lang="less" scoped>
@themeColor: #1890FF;
.m-slider {
  display: inline-block;
  height: 4px;
  position: relative;
  z-index: 9;
  touch-action: none; // 禁用元素上的所有手势,使用自己的拖动和缩放api
  .u-slider-rail { // 灰色未选择滑动条背景色
    position: absolute;
    z-index: 99;
    height: 4px;
    width: 100%;
    background: #f5f5f5;
    border-radius: 2px;
    cursor: pointer;
    transition: background .3s;
  }
  .u-slider-track { // 蓝色已选择滑动条背景色
    position: absolute;
    z-index: 99;
    background: #91d5ff;
    border-radius: 4px;
    height: 4px;
    cursor: pointer;
    transition: background .3s;
    pointer-events: none;
  }
  .trackTransition {
    transition: left .2s, width .2s, background .3s;
  }
  &:hover {
    .u-slider-rail { // 灰色未选择滑动条背景色
      background: #E3E3E3;
    }
    .u-slider-track { // 蓝色已选择滑动条背景色
      background: @themeColor;
    }
  }
  .u-slider-handle { // 滑块
    position: absolute;
    z-index: 999;
    width: 12px;
    height: 12px;
    top: -6px;
    background: #fff;
    border: 2px solid #91d5ff;
    border-radius: 50%;
    cursor: pointer;
    transition: border-color .3s,box-shadow .6s,transform .3s cubic-bezier(.18,.89,.32,1.28);
    &:focus {
      border-color: @themeColor;
      box-shadow: 0 0 0 5px rgba(24, 144, 255, 0.2);
    }
    &:hover {
      border-color: @themeColor;
    }
  }
  .handleTransition {
    transition: left .2s, border-color .3s,box-shadow .6s,transform .3s cubic-bezier(.18,.89,.32,1.28);
  }
}
.disabled {
  cursor: not-allowed;
  .u-slider-rail {
    pointer-events: none;
  }
  .u-slider-track {
    background: rgba(0, 0, 0, .25);
  }
  .u-slider-handle {
    border-color: rgba(0, 0, 0, .25);
    pointer-events: none;
  }
  &:hover {
    .u-slider-track {
       background: rgba(0, 0, 0, .25);
    }
  }
}
</style>

②在要使用的页面引入:

<div class="m-num">
    <p class="u-num">{
  { value[0] }}</p>
    <p class="u-num">{
  { value[1] }}</p>
</div>
<NumSlider
    :min="0"
    :max="100"
    :initialValue="[20, 80]"
    :width="1200"
    :disabled="false"
    :range="true"
    v-model="value"
    @change="onChange"
/>
import NumSlider from '@/components/NumSlider'
components: {
    NumSlider
}
data () {
    return {
        value: [20, 80]
    }
}
methods: {
    onChange (val) {
      console.log('change:', val)
    }
}
.m-num {
  min-width: 1200px;
  width: 1200px;
  margin: 0 auto;
  display: flex;
  justify-content: space-between;
  .u-num {
    color: #333;
    font-size: 24px;
  }
}
相关文章
|
6月前
|
JavaScript
vue element plus Slider 滑块
vue element plus Slider 滑块
176 0
|
3月前
|
移动开发 资源调度 JavaScript
Vue2使用触摸滑动插件(Swiper)
这篇文章介绍了在Vue 3框架中如何使用Swiper插件来创建不同类型的触摸滑动组件,包括轮播图、淡入淡出效果和走马灯效果,并提供了详细的配置选项和使用示例。
304 1
Vue2使用触摸滑动插件(Swiper)
|
3月前
|
JavaScript
Vue3滑动输入条(Slider)
这是一个可高度定制的滑动输入条组件,支持多种配置选项,如宽度、最小值、最大值、是否禁用、双滑块模式等。主要功能包括点击滑动条快速定位并获取数值、拖动滑块调整数值、键盘操作调整数值以及自定义Tooltip显示格式。组件通过监听DOM尺寸变化来动态调整布局,并利用requestAnimationFrame优化动画效果,提供了丰富的交互体验。在线预览和详细代码示例可见[这里](https://themusecatcher.github.io/vue-amazing-ui/guide/components/slider.html)。
Vue3滑动输入条(Slider)
|
3月前
|
JavaScript API UED
Vue3使用触摸滑动插件(Swiper)
本文介绍如何在Vue2项目中使用Swiper插件实现触摸滑动功能,并封装了两种轮播图展示形式:首页轮播图(`type: banner`)和走马灯轮播图(`type: carousel`),以及信息展播模式(`type: broadcast`)。支持自定义轮播图片、区域尺寸、动画效果等属性。通过示例代码展示了不同切换动画及自定义效果,并提供了在线预览。适用于多种应用场景,提升用户体验。
Vue3使用触摸滑动插件(Swiper)
|
3月前
|
JavaScript
Vue3滚动条(Scrollbar)
这是一个基于 Vue 的自定义滚动条组件 Scrollbar.vue,提供了丰富的配置选项和方法。通过参数如 `contentClass`、`size` 和 `trigger` 等,可以灵活控制滚动条的样式和行为。
Vue3滚动条(Scrollbar)
|
3月前
Vue3走马灯(Carousel)
这是一个基于 Vue2 的走马灯(Carousel)组件,支持丰富的自定义配置。主要属性包括图片数组、宽度、高度、自动切换、暂停轮播、过渡效果、轮播间隔、箭头和指示点等。组件提供了多种过渡效果(如滑动和渐变)及动画时长设置,并允许自定义箭头和指示点的样式。此外,还支持通过键盘方向键进行切换,提供了灵活的使用方法。
Vue3走马灯(Carousel)
|
3月前
Vue2走马灯(Carousel)
这是一个基于 Vue2 的走马灯轮播组件(Carousel),支持鼠标移入暂停、移出后自动轮播。用户可以自定义设置轮播图片数组、滑动间隔时间、图片宽高。该组件提供了两种滑动效果实现方式:一种是通过 `setInterval` 延时调用,另一种是使用 `requestAnimationFrame()`,后者效果更佳。组件还支持图片懒加载,适用于多种应用场景。
179 0
Vue2走马灯(Carousel)
|
3月前
|
JavaScript
Vue2走马灯扩展版(Carousel)
这篇文章介绍了如何在Vue 3框架中创建一个可自定义的走马灯(Carousel)组件,支持自动播放、导航、分页和响应用户交互等功能。
107 0
Vue2走马灯扩展版(Carousel)
|
6月前
|
JavaScript 容器
vue element plus Scrollbar 滚动条
vue element plus Scrollbar 滚动条
164 0
|
6月前
|
JavaScript
Vue中的过渡效果和动画有何不同?
Vue中的过渡效果和动画有何不同?
36 3