Vue <滑块拖动>

2021-04-07 15:29:18 浏览数 (1)

类似于滑块拖动很多组件都有,需求不复杂的可以直接用第三方组件的。但是如果碰到渐变拖动相信一大部分组件都没有,所以就要想办法自己封装了,其实原理还是很简单的。›

知识点:

  1. background: linear-gradient 背景渐变属性
  2. clip-path: polygon 背景裁切属性
  3. 移动端ontouchstart,ontouchmove,ontouchend和Pc 端onmousedown,onmousemove,onmouseup

组件使用:

代码语言:javascript复制
<template>
  <div class="body">
    <slider :planNum.sync="plan" :color="['#D6FF7F','#00B3CC']"></slider>
    <slider :planNum.sync="plan1" :color="['#ED7B84','#9055FF']"></slider>
    <slider :planNum.sync="plan2" :color="['#2F80ED']"></slider>
    <slider :planNum.sync="plan3"></slider>
  </div>
</template>

<script>
import slider from '../common/slider'
export default {
  components: {
    slider
  },
  data() {
    return {
      plan: 75,
      plan1: 45,
      plan2: 100,
      plan3: 88
    }
  },
  methods: {
  }
}
</script>

<style lang="scss" scoped>
.body {
  display: inline-block;
  margin: 50px auto;
}
</style>

组件封装:slider.vue

代码语言:javascript复制
<template>
  <div class="plan_box" ref="wrapper">
    <div
      class="plan"
      :style="`clip-path: polygon(0 0,${plan}% 0,${plan}% 100%,0 100%);background: linear-gradient(to left, ${this.gradient});`"
    ></div>
    <div class="slider" ref="slider">
      <span class="text">{{planNum}}%</span>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    planNum: Number, //进度数值
    color: { //背景颜色,['#e233ff'] 为单色 ,['#e233ff', '#ff6b00']为渐变色
      type: Array,
      default: function() {
        return ['#e233ff', '#ff6b00']
      }
    }
  },
  computed: {
    plan: {
      get() {
        return this.planNum
      },
      set(val) {
        this.$emit('update:planNum', Number(val))
      }
    },
    gradient() {
      if (this.color.length > 1) {
        return this.color.join(',')
      } else {
        return `${this.color[0]},${this.color[0]}`
      }
    }
  },
  data() {
    return {
      //   plan: 55
    }
  },
  mounted() {
    this.init(this.$refs.wrapper)
  },
  methods: {
    //pc端鼠标拖动
    mouseDown(el) {
      var _this = this
      var $el = el
      var slider = _this.$refs.slider
      var rect = $el.getBoundingClientRect()
      if (_this.plan) {
        let plan = _this.plan
        slider.style.left = (plan / 100) * rect.width   'px'
      }
      slider.onmousedown = function(event) {
        event.preventDefault()
        document.onmousemove = function(e) {
          var sliderX = e.clientX - rect.left
          if (sliderX < 0) {
            sliderX = 0
          } else if (sliderX > rect.width) {
            sliderX = rect.width
          }
          //   console.log(sliderX)
          //滑块的位置
          slider.style.left = sliderX   'px'
          //进度条的长度
          _this.plan = ((sliderX / rect.width) * 100).toFixed(0)
        }
        document.onmouseup = function() {
          document.onmousemove = null
          document.onmousedown = null
        }
      }
    },
    touchStart(el) {
      var _this = this
      var $el = el
      var slider = _this.$refs.slider
      var rect = $el.getBoundingClientRect()
      if (_this.plan) {
        let plan = _this.plan
        slider.style.left = (plan / 100) * rect.width   'px'
      }
      slider.ontouchstart = function(event) {
        event.preventDefault()
        document.ontouchmove = function(e) {
          var oEvent = e.touches[0]
          var sliderX = oEvent.clientX - rect.left
          if (sliderX < 0) {
             sliderX = 0
          } else if (sliderX > rect.width) {
            sliderX = rect.width
          }
          // console.log(sliderX)
          //滑块的位置
          slider.style.left = sliderX   'px'
          //进度条的长度
          _this.plan = ((sliderX / rect.width) * 100).toFixed(0)
        }
        document.ontouchend = function() {
          document.ontouchmove = null
          document.ontouchstart = null
        }
      }
    },
    init(el) {
      // 判断是否为移动设备
      if (/Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)) {
        this.touchStart(el)
      } else {
        this.mouseDown(el)
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.plan_box {
  margin: 50px 0;
  height: 11px;
  width: 300px;
  // border: 1px solid black;
  background: #f1f1f1;
  box-sizing: border-box;
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  border-radius: 5px;
  .plan {
    width: 100%;
    height: 100%;
    position: absolute;
    left: 0;
    top: 0;
    // background: black;

    border-radius: 5px;
  }
  .slider {
    cursor: grab;
    position: absolute;
    left: 0px;
    &::before {
      content: '';
      display: block;
      width: 20px;
      height: 20px;
      border-radius: 50%;
      background: white;
      box-shadow: 2px 2px 4px #919191;
      position: absolute;
      left: -10px;
      top: -10px;
    }
    .text {
      font-size: 12px;
      position: absolute;
      display: inline-block;
      padding: 5px;
      border-radius: 3px;
      background: white;
      top: -45px;
      left: -20px;
      box-shadow: 2px 2px 4px #d3d3d3;
    }
  }
}
</style>

0 人点赞