vue项目双滑块组件

先看效果图:

说明:两端值300,750 是可选范围的最大值;两个按钮上的值是已经选择的范围 ;

目前灰色背景条的宽度单位是px,

 上面代码中,背景条宽度是写死的;下面是优化后的代码:

<template>
  <div
    :style="{
      display: 'flex',
      'justify-content': 'center',
      width: '100%',
    }"
  >
    <div
      class="slider-box"
      id="slider-box"
      :style="{
        width: '100%',
        background: outBg,
      }"
      @mousedown="handleClickZong"
    >
      <div
        :class="['slider-nei', isClick ? 'transtion' : '']"
        :style="{
          width: Math.abs(moveDistanceOne - moveDistanceTwo) + 20 + 'px',
          transform:
            moveDistanceTwo > moveDistanceOne
              ? `translateX(${moveDistanceOne}px)`
              : `translateX(${moveDistanceTwo}px)`,
          background: neiBg,
        }"
      ></div>
      <div
        :style="{
          transform: `translateX(${moveDistance}px)`,
        }"
        :class="{
          'point-box': true,
          zhua: isMove,
          transtion: isClick,
        }"
        v-if="!range"
        @mousedown.stop.prevent="handleMousedown"
      ></div>
      <div
        :style="{
          transform: `translateX(${moveDistanceOne}px)`,
          background: btnBg,position:'absolute','z-index': leftIndex
        }"
        :class="{
          'point-box': true,
          zhua: isMove,
          transtion: isClick,
        }"
        v-if="range"
        @mousedown.stop.prevent="handleMousedownOne"
        @touchstart="handleMousedownOne1"
        @mouseup="handleUp"
        @touchend="handleUp"
      >
        {{ Math.trunc(moveDistanceOne * rate) + min }}
      </div>
      <div
        :style="{
          transform: `translateX(${moveDistanceTwo}px)`,
          background: btnBg,position:'absolute','z-index': rightIndex
        }"
        :class="{
          'point-box': true,
          point: true,
          zhua: isMove,
          transtion: isClick,
        }"
        @mousedown.stop.prevent="handleMousedownTwo"
        @touchstart="handleMousedownTwo1"
        @mouseup="handleUp"
        @touchend="handleUp"
      >
        {{ Math.trunc(moveDistanceTwo * rate + min) }}
      </div>
    </div>
  </div>
</template>
<script>
import { mapGetters } from "vuex";
export default {
  data() {
    return {
      range: true, //是否开启双滑块
      isClick: false, //是否直接点击
      isMove: false, //是否处于滑动状态
      flag: false, //
      moveDistance: 0,
      initX: 0, //记录鼠标点下时的坐标,用于移动中求差值
      moveStart: 0, //进度条的开始位置
      moveEnd: 0, //进度条的结束位置
      moveDistanceOne: 0, //滑块一的位置
      moveDistanceTwo: 50, //滑块二的位置
      rate: 1, // 比率
      outerWidth: 100,
      rate1: 1, // 比率
      outerWidth1: 100,
      valueRange: [],
      leftIndex: 0,
      rightIndex: 0.5,
    };
  },
  computed: {
    // 使用对象展开运算符将 getter 混入 computed 对象中
    ...mapGetters("common", [
      "userType"
    ]),
  },
  props: {
    // 可选择范围的较大值
    max: {
      type: Number,
      default: 750,
    },
    // 外层背景色
    outBg: {
      type: String,
      default: "#F0F0F0",
    },
    // 滑块背景色
    btnBg: {
      type: String,
      default: "#497cfe",
    },
    // 内层背景色
    neiBg: {
      type: String,
      default: "#E5EDFF",
    },
    // 可选择范围的较小值
    min: {
      type: Number,
      default: 150,
    },
    // 已经选择的范围
    valuesRange: {
      type: Array,
      default: [350, 550],
    },
  },
  watch: {
    valuesRange: {
      handler(val1) {
        this.valueRange = val1;
        this.init();
      },
      deep: true,
      immediate: true,
    },
  },
  mounted() {
    window.addEventListener("resize", this.init);
    window.addEventListener("mouseup", () => {
      if(this.flag) {
        this.handleUp2();
        this.flag = false;
      }
    });
    // this.init();
  },
  methods: {
    init() {
      this.$nextTick(() => {
        /* this.valueRange [1, 750] */
        if (this.valueRange && this.valueRange.length > 0) {
          let max_min = this.max - this.min;
          var slide_width = document.querySelector("#slider-box").clientWidth;
          var point_width = document.querySelector(".point").clientWidth;
          this.outerWidth = slide_width - point_width;
          this.outerWidth1 = slide_width - point_width -  point_width;
          this.rate = max_min / this.outerWidth;
          this.rate1 = max_min / this.outerWidth1;
          let vr = JSON.parse(JSON.stringify(this.valueRange));
          if(vr[0] > vr[1]) {
            this.valueRange = [vr[1],vr[0]];
          }
          this.moveDistanceOne = (this.valueRange[0] - this.min) / this.rate;
          this.moveDistanceTwo = (this.valueRange[1] - this.min) / this.rate;
          this.$forceUpdate();
        }
      });
    },
    //移动端 touchstart 点击监听 ontouchmove 移动监听 ontouchend 松开监听,e.changedTouches[0] 元素偏移的一些数据
    //PC端 mousedown 点击监听 onmousemove 移动监听 onmouseup 松开监听
    /**
     * 初始坐标就是鼠标点下时的clientX坐标,这样就可以做到将slider放在页面任何位置,拖动原点偏移的量也是正确的,
     * 因为原点移动距离是用鼠标移动的位置和鼠标点下的位置做差值计算,所以不用担心这里的clientX会因为slider放在
     * 别的地方而导致距离计算错误
     * @param e
     */
    //鼠标点击
    handleMousedown(e) {
      this.isMove = true;
      this.initX = e.clientX;
      const sliderDomWidth = this.outerWidth;
      // const sliderDomWidth = document.getElementsByClassName("slider-box")[0].clientWidth;
      document.onmousemove = (e) => {
        if (this.isMove) {
          this.moveDistance += e.clientX - this.initX;
          this.initX = e.clientX;
          if ((this.moveDistance / sliderDomWidth) * 100 > 100) {
            this.moveDistance = sliderDomWidth;
            return;
          }
          if ((this.moveDistance / sliderDomWidth) * 100 < 0) {
            this.moveDistance = 0;
            return;
          }
        }
      };
      document.onmouseup = (e) => {
        this.isMove = false;
        document.onmousemove = null;
      };
    },
    handleUp(){
      // console.log('this.valueRange', this.valueRange);
      // this.$emit("recommendRange", this.valueRange);
    },
    handleUp2(){
      this.$emit("recommendRange", this.valueRange);
    },
    handleUp3(){
      this.$emit("recommendRange", this.valueRange);
    },
    handleUp4(){
      this.$emit("recommendRange", this.valueRange);
    },
    /**
     * 当点击进度条某一个位置时,快捷设置进度条的位置,这里就需要用offsetX而不是clientX了。这里需要设置的便宜距离是鼠标距离目标元素的距离而不是鼠标在整个页面上的坐标
     * @param e
     */
    handleClickZong(e) {
      this.isClick = true;
      setTimeout(() => {
        this.isClick = false;
      }, 300);
      this.moveDistance = e.offsetX - 10;
    },
    //滑动滑块1
    handleMousedownOne1(e) {
      if (this.userType != 'VIP') {
        this.$store.commit('common/SET_SHOWEXCHANGEVIP', true);
        return;
      }
      this.flag = true;
      this.isMove = true;
      this.leftIndex = 0.5;
      this.rightIndex = 0;
      let currentDistance = e.changedTouches[0].clientX;
      document.ontouchmove = (e) => {
        let item = e.changedTouches[0];
        if (this.isMove) {
          const moveX = item.clientX - currentDistance;
          currentDistance = item.clientX;
          this.moveDistanceOne += moveX;
          if (this.moveDistanceOne < 0) {
            this.moveDistanceOne = 0;
            return;
          }
          if (this.moveDistanceOne > this.moveDistanceTwo) {
            this.moveDistanceOne = this.moveDistanceTwo;
            return;
          }
          this.valueRange = [this.moveDistanceOne, this.moveDistanceTwo];
        }
      };
      document.ontouchend = (e) => {
        this.isMove = false;
        // this.flag = false;
        document.onmousemove = null;
      };
    },
    handleMousedownOne(e) {
      console.log(e);
      if (this.userType != 'VIP') {
        this.$store.commit('common/SET_SHOWEXCHANGEVIP', true);
        return;
      }
      this.flag = true;
      this.isMove = true;
      this.leftIndex = 0.5;
      this.rightIndex = 0;
      let currentDistance = e.clientX;
      document.onmousemove = (e) => {
        if (this.isMove) {
          /* moveX 滑块横向移动的距离 */
          const moveX = e.clientX - currentDistance;
          currentDistance = e.clientX;
          this.moveDistanceOne += moveX;
          if (this.moveDistanceOne < 0) {
            this.moveDistanceOne = 0;
            return;
          }
          if (this.moveDistanceOne > this.moveDistanceTwo) {
            this.moveDistanceOne = this.moveDistanceTwo;
            return;
          }
          
          let arr_one = Math.trunc(this.moveDistanceOne * this.rate) + this.min;
          let arr_two = Math.trunc(this.moveDistanceTwo * this.rate) + this.min;
          this.valueRange = [arr_one, arr_two];
        }
      };
      document.onmouseup = (e) => {
        this.isMove = false;
        // this.flag = false;
        document.onmousemove = null;
      };
    },
    //滑动滑块2
    handleMousedownTwo1(e) {
      if (this.userType != 'VIP') {
        this.$store.commit('common/SET_SHOWEXCHANGEVIP', true);
        return;
      }
      this.isMove = true;
      this.flag = true;
      this.leftIndex = 0;
      this.rightIndex = 0.5;
      let currentDistance = e.changedTouches[0].clientX;
      document.ontouchmove = (e) => {
        if (this.isMove) {
          let item = e.changedTouches[0];
          const moveX = item.clientX - currentDistance;
          currentDistance = item.clientX;
          this.moveDistanceTwo += moveX;
          if (this.moveDistanceTwo > this.outerWidth) {
            this.moveDistanceTwo = this.outerWidth;
            return;
          }
          if (this.moveDistanceTwo < this.moveDistanceOne) {
            this.moveDistanceTwo = this.moveDistanceOne;
            return;
          }
          if (this.moveDistanceTwo < 0) {
            this.moveDistanceTwo = 0;
            return;
          }
          this.valueRange = [this.moveDistanceOne, this.moveDistanceTwo];
        }
      };
      document.ontouchend = (e) => {
        this.isMove = false;
        // this.flag = false;
        document.onmousemove = null;
      };
    },
    //滑动滑块2
    handleMousedownTwo(e) {
      if (this.userType != 'VIP') {
        this.$store.commit('common/SET_SHOWEXCHANGEVIP', true);
        return;
      }
      this.flag = true;
      this.isMove = true;
      this.leftIndex = 0;
      this.rightIndex = 0.5;
      let currentDistance = e.clientX;
      document.onmousemove = (e) => {
        if (this.isMove) {
          const moveX = e.clientX - currentDistance;
          currentDistance = e.clientX;
          this.moveDistanceTwo += moveX;
          if (this.moveDistanceTwo > this.outerWidth) {
            this.moveDistanceTwo = this.outerWidth;
            return;
          }
          if (this.moveDistanceTwo < this.moveDistanceOne) {
            this.moveDistanceTwo = this.moveDistanceOne;
            return;
          }
          if (this.moveDistanceTwo < 0) {
            this.moveDistanceTwo = 0;
            return;
          }
          let arr_one = Math.trunc(this.moveDistanceOne * this.rate) + this.min;
          let arr_two = Math.trunc(this.moveDistanceTwo * this.rate) + this.min;
          this.valueRange = [arr_one, arr_two];
        }
      };
      document.onmouseup = (e) => {
        this.isMove = false;
        // this.flag = false;
        document.onmousemove = null;
      };
    },
  },
};
</script>
<style lang="scss" scoped>
@function autoPx($num) {
  @return (($num / 1200) * 24rem);
}
.slider-box {
  height: autoPx(10);
  border-radius: autoPx(20);
  position: relative;
}

.slider-nei {
  position: absolute;
  left: 0;
  top: 0;
  width: 0;
  height: autoPx(10);
  border-radius: autoPx(20);
}

.point-box {
  width: autoPx(43);
  height: autoPx(20);
  border-radius: autoPx(20);
  position: absolute;
  top: -(autoPx(5));
  color: #fff;
  font-size: autoPx(12);
  line-height: autoPx(20);
  text-align: center;
  user-select: none;
  cursor: pointer;
}

.point-box:hover {
  cursor: grab;
}

.zhua:active {
  cursor: grabbing;
}

.transtion {
  transition: all 0.3s;
}
</style>

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值