component 滑动尺子 - 丝滑版

<template>
  <div class="ruler-wrap">
    <div class="ruler-box" ref="wrap">
      <div class="highlight" :style="{ left: indexBarP(),background:indexColor }"></div>
      <div class="scroll">
        <div class="ruler" ref="ruler" :style="{width:rulerWidth}"></div>
      </div>
      <div class="number">
        <span v-for="(item, index) in itemCount" :key="index">{{invidatorMin + index * step}}</span>
      </div>
      <img
          src="https://files.lifesense.com/other/20200401/384b6ca2045f4376b214d2159fe91b4b.png"
          class="shadow left"
      />
      <img
          src="https://files.lifesense.com/other/20200401/384b6ca2045f4376b214d2159fe91b4b.png"
          class="shadow right"
      />
    </div>
  </div>
</template>

<script>
  let timer;
  export default {
    name: "Ruler",
    props: {
      min: {
        type: Number,
        default: 40,
        required: true
      },
      max: {
        type: Number,
        default: 220,
        required: true
      },
      value: {
        type: Number,
        default: 90,
        required: true
      },
      indexColor: {
        type: String,
        default: "#16c5ef"
      },
      step: {
        type: Number,
        default: 10
      },
      accuracy: {
        type: Number,
        default: 0
      }
    },
    data() {
      return {
        rem: 16,
        unitW: 8,
        indexBarPosition: 0,
        currValue: 20,
        itemCount: 0,
        el: null,
        invidatorMin: this.min,
        invidatorMax: this.max
      };
    },
    methods: {
      indexBarP() {
        return (this.indexBarPosition / this.rem + 0.05) + "rem";
      },
      initScroll() {
        let wholeWidth = this.$refs.ruler.offsetWidth;
        this.el = this.$refs.wrap;
        let unitW = wholeWidth / ((this.itemCount + 5) * 10);
        this.unitW = unitW;
        this.indexBarPosition = Math.floor(this.el.offsetWidth / 2);
        let leftPeak =
          25 * unitW -
          this.indexBarPosition +
          1.5 +
          (this.min - this.invidatorMin / this.step) * 10 * this.unitW; //左边峰值,禁止超出
        let rightPeak =
          ((this.max - this.min) / this.step) * 10 * this.unitW + leftPeak;

        this.el.onscroll = e => {
          let scrollLeft = e.target.scrollLeft;
          let value = this.accuracy
            ? Number(
              (((scrollLeft - leftPeak) / this.unitW / 10) * this.step).toFixed(
                this.accuracy
              )
            )
            : Math.round(((scrollLeft - leftPeak) / this.unitW / 10) * this.step);
          let realValue = this.min + value;
          this.currValue =
            realValue >= this.max
              ? this.max
              : realValue <= this.min
              ? this.min
              : realValue;
          clearTimeout(timer);
          let params = {
            scrollLeft,
            leftPeak,
            rightPeak,
            unitW,
            time: new Date().getTime()
          };
          timer = setTimeout(this.adjust,100, params);
        };
      },
      adjust(params) {
        console.log(params.scrollLeft + ':' +this.el.scrollLeft);
        if (params.scrollLeft === this.el.scrollLeft) {
          if (params.scrollLeft < params.leftPeak) {
            this.el.scrollTo(params.leftPeak, 0);
          } else if (params.scrollLeft > params.rightPeak) {
            this.el.scrollTo(params.rightPeak, 0);
          } else if (
            Math.floor(params.scrollLeft) !== Math.floor(params.leftPeak) &&
            Math.floor(params.scrollLeft) !== Math.floor(params.rightPeak)
          ) {
            let end = params.scrollLeft;
            let canMove = Math.round(end / params.unitW) * params.unitW + 2;
            this.el.scrollTo(canMove, 0);
          }
        }
      },
      init() {
        let wholeWidth = this.$refs.ruler.offsetWidth; //游标卡尺总宽度
        this.el = this.$refs.wrap;
        let unitW = wholeWidth / ((this.itemCount + 5) * 10); //每个小格子站的宽度
        this.unitW = unitW;
        //中间索引条位置
        this.indexBarPosition = Math.floor(this.el.offsetWidth / 2);
        let leftPeak =
          25 * unitW -
          this.indexBarPosition +
          1.5 +
          (this.min - this.invidatorMin / this.step) * 10 * this.unitW; //左边峰值,禁止超出
        let rightPeak =
          ((this.max - this.min) / this.step) * 10 * this.unitW + leftPeak;
        let initialP =
          leftPeak + (((this.value - this.min) * 10) / this.step) * unitW;
        this.el.scrollTo(initialP, 0);
        this.initScroll();
      }
    },
    created() {
      this.invidatorMin = Math.floor(this.min);
      this.invidatorMax = Math.ceil(this.max);
      this.itemCount =
        Math.ceil(this.invidatorMax - this.invidatorMin) / this.step + 1;
      this.rem = (document.documentElement.offsetWidth / 375) * 16;
      this.currValue = this.value;
    },
    mounted() {
      this.init();
    },
    watch: {
      currValue(value) {
        this.$emit("change", value);
      }
    },
    computed: {
      rulerWidth() {
        return (this.itemCount + 5) * 25 + "vw";
      }
    }
  };
</script>

<style lang="less" scoped>
  .ruler-wrap {
    position: relative;
  }
  .ruler-box {
    overflow-x: scroll;
    height: 72px;
    background: linear-gradient(
        270deg,
        rgba(251, 251, 251, 1) 0%,
        rgba(255, 255, 255, 0) 100%
    );
    &::-webkit-scrollbar {
      display: none;
    }
  }
  .number {
    white-space: nowrap;
    margin-top: -30px;
    span {
      display: inline-block;
      width: 25vw;
      height: 12px;
      flex: 1;
      text-align: center;
      color: #999999;
      &:first-of-type {
        margin-left: 50vw;
      }
    }
  }
  .scroll {
    position: relative;
    width: 100%;
    height: 72px;
    border-radius: 4px;
    .ruler {
      height: 36px;
      display: flex;
      background-image: url('https://files.lifesense.com/other/20210225/e912461b411b45eda1215d081476b3b9.png');
      background-position: 12.5vw 0;
      background-size: 100vw 37px
    }
  }
  .highlight {
    position: absolute;
    top: 0;
    left: 50%;
    transform: translateX(-100%);
    width: 0.9vw;
    height: 32px;
    background-color: #16c5ef;
    border-radius: 0 0 2px 2px;
    z-index: 1;
  }
  .shadow {
    position: absolute;
    height: 100%;
    width: 120px;
    pointer-events: none;
    &.left {
      left: 0;
      top: 0;
    }
    &.right {
      right: 0;
      top: 0;
      transform: rotate(180deg);
    }
  }
</style>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值