vue刻度尺组件 【cs-ruler】 重写可自定义小数位数

一、依赖使用
安装依赖
cnpm install cs-ruler
main.js中引入
import CsRuler from 'cs-ruler' 
Vue.use(CsRuler)
代码 使用
<template>
  <section>
<!--pointerColor 指针颜色; numSize 字体大小; maxNum 最大值 minNum 最小值; NowNum当前值(默认100);
    ispoint开启小数[默认一位小数];ruleWidth:配置一页展示格数(默认40个)-->
<!--@post-NumValue来接收滚动的值 @scroll-start="startEvent"开始滚动后发送给父级消息事件 @scroll-end="endEvent"滚动结束后发送给父级消息事件-->
      <cs-ruler
        :pointer-color="pointerColor"
        :num-size="30"
        :NowNum="detail.tmda"
        :ispoint="pointFlag"
        :ruleWidth="40"
        @post-NumValue="rulerNum"></cs-ruler>
  </section>
</template>
import ruler from 'cs-ruler'
export default {
  name: 'inputTmxx',
  components: {
    'cs-ruler': ruler.CsingRuler
  },
  data () {
    return {
       detail: {
         tmmc: '您的身高是?',
         unit: 'cm',
         pointFlag: 'true',
         tmda: 8
       },
      pointerColor: '#5081FF'
    }
  },
  methods: {
    //子组件传递刻度表
   rulerNum (val) {
    this.detail.tmda = val
   }
  }
}
示例:
二、组件重写使用
组件使用方法(便于区分,更换了组件名字)
  <div>     
     <ruler-drag
        :pointer-color="pointerColor"
        :num-size="30"
        :NowNum="detail.tmda"
        ispoint
        :pointLen="100" // 可自定义小数位数:10一位;100两位;...
        @post-NumValue="rulerNum"></ruler-drag>
    </div>
const RulerDrag = () => import('@/components/rulerDrag')
export default {
  name: '',
  components: {
    RulerDrag
  },
}

 

组件源码
<template>
  <div>
    <div class="cs-rule" ref="rulepage">
      <!--刻度表-->
      <div class="cs-scrollrule" ref="scrollrule">
        <ul class="cs-scrollrule-hook" ref="rulehook">
          <!--0刻度前的空白-->
          <div class="cs-rule-null">
            <li v-for="(item,index) in zeroList" class="cs-scroll-item" :key="index"></li>
          </div>
          <!--正常刻度表-->
          <template v-for="(item,index) in counter">
            <li class="cs-scroll-item" :key="index">
              <template v-if="index % 10 == 0">
                <div class="cs-scroll-item-rule vux-1px-l cs-scale-integer"></div>
                <div v-if="ispoint" class="cs-scroll-item-num">{{ (index + minNum) / pointLen }}</div>
                <div v-else class="cs-scroll-item-num">{{ (index + minNum ) * oneGridValue }}</div>
              </template>
              <template v-else-if="index % 5 == 0">
                <div class="cs-scroll-item-rule vux-1px-l cs-scale-half"></div>
              </template>
              <template v-else>
                <div class="cs-scroll-item-rule vux-1px-l cs-scale-one"></div>
              </template>
            </li>
          </template>
          
          <!-- 最大刻度后面的空白 -->
          <div class="cs-rule-null-after">
            <li v-for="(item,index) in aletrList" class="cs-scroll-item" :key="index"></li>
          </div>
          
        </ul>
      </div>
      <!--刻度表的针-->
      <div class="cs-scroll-item-pointer"></div>

    </div>
  </div>
</template>

<script>
  import BScroll from 'better-scroll'

  export default {
    name: 'cs-ruler',
    props: {
      // 初始值
      NowNum: {
        type: Number,
        default: 100
      },
      // 最大刻度
      maxNum: {
        type: Number,
        default: 1000
      },
      // 最小刻度
      minNum: {
        type: Number,
        default: 0
      },
      // 指针颜色
      pointerColor: {
        type: String,
        default: 'rgb(97,206,81)'
      },
      // 刻度尺有多细
      ruleWidth: {
        type: Number,
        default: 40
      },
      // 字体大小
      numSize: {
        type: Number,
        default: 50
      },
      // 是否启用小数
      ispoint: {
        type: Boolean,
        default: false
      },
      // 小数位数
      pointLen: {
        type: Number,
        default: 1
      },
      // 每个格子多大
      oneGridValue: {
        type: Number,
        default: 1
      }
    },
    data() {
      return {
        // 由于v-for循环的时候,按照index计数的,所以最后一个值不会显示,需要+1,则刻度尺后面的空白就要+1
        // counter: this.maxNum - this.minNum + 1, // 因为可能需要动态修改maxNum和minMun,所以放在计算属性中
        //0刻度前面的空白,
        zeroList: this.ruleWidth / 2,
        // 刻度结束后的空白
        aletrList: this.ruleWidth / 2 - 1,
      }
    },
    methods: {
      // 全局初始化
      init(){
      this.NowNum = this.NowNum * this.pointLen // 需要加上,否则小数回显会有问题
this.$nextTick(() => {
          this.initScroll();
          this.calculateWidth();
          // this.NowNum - this.minNum 当前值-最小值才是初始化需要滚动的值
          this.scrollrule.scrollBy(-(this.oneWidth * (this.NowNum - this.minNum) ), 0, 0)
        });
      },
      // 初始化滚动
      initScroll() {
        this.scrollrule = new BScroll(this.$refs.scrollrule, {
          // 实时监听滚动的位置并返回
          probeType: 3,
          scrollX: true,
        })
        
        // 监听滚动开始
        this.scrollrule.on('scrollStart', () => {
          this.$emit('scroll-start', true)
        })

        // 监听滚动
        this.scrollrule.on('scroll', (pos) => {
          this.scrollX = Math.abs(Math.round(pos.x))
          let NumValue = Math.abs(Math.round(this.scrollX / this.oneWidth)) + this.minNum
          // 判断是否开启小数
          if(this.ispoint){
            this.$emit('post-NumValue', NumValue / this.pointLen * this.oneGridValue )
          }else{
            this.$emit('post-NumValue', NumValue * this.oneGridValue )
          }
        })

        //滚动结束监听
        this.scrollrule.on('scrollEnd', () => {
          //滑动后的小距离
          let littleNum = this.scrollX % this.oneWidth
          //计算距离下一个刻度的差值
          let vul = this.oneWidth - littleNum
          // 加入差值比较大,再进行吸附,大于一半的距离,就往右边吸附差值的距离,小于一半的距离,就往左边吸附滑动的距离
          if (vul > 0.5 && vul < (this.oneWidth - 0.5)) {
            if (littleNum > (this.oneWidth / 2)) {
              this.scrollrule.scrollBy(-vul, 0, 0)
            } else {
              this.scrollrule.scrollBy(littleNum, 0, 0)
            }
          }
          // 滚动结束给父级发送一个事件
          // 初始化时调整了一次值,所以也会有一个true
          // 第一次true是因为滚动结束,第二个true是因为位置微调了一次,所以又滚动了
          this.$emit('scroll-end', true)
        })

      },
      // 获取宽度用于计算滚动区域
      calculateWidth() {
        // 获取右侧菜单每一个的li
        let goodsList = this.$refs.rulehook
        let listWidth = goodsList.clientWidth
        let listNum = this.counter + this.zeroList + this.aletrList
        // 每一格的距离大小
        this.oneWidth = listWidth / listNum
      },
      // 获取指针颜色等信息
      getMainValue(){
        const docStyle = this.$refs.rulepage.style;
        // 指针颜色
        docStyle.setProperty('--pointer-color', this.pointerColor);
        // 字体大小
        docStyle.setProperty('--num-size', this.numSize);
        // 刻度尺宽度
        docStyle.setProperty('--rule-width', this.ruleWidth);
        
      },
      // 暴露给父级,如果后期需要修改某些参数,需要重新初始化一下组件
      initRule(){
        this.init()
        this.getMainValue()
      }
    },
    computed: {
      counter(){
        return this.maxNum - this.minNum + 1
      }
    },
    created() {
      this.init()
    },
    mounted() {
      this.getMainValue()
    },
    components: {

    },
    watch: {

    }
  }
</script>

<style lang="less">
  .setTopLine(@c: #C7C7C7) {
    content: " ";
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    height: 1px;
    border-top: 1px solid @c;
    color: @c;
    transform-origin: 0 0;
    transform: scaleY(0.5);
  }

  .setBottomLine(@c: #C7C7C7) {
    content: " ";
    position: absolute;
    left: 0;
    bottom: 0;
    right: 0;
    height: 1px;
    border-bottom: 1px solid @c;
    color: @c;
    transform-origin: 0 100%;
    transform: scaleY(0.5);
  }

  .setLeftLine(@c: #C7C7C7) {
    content: " ";
    position: absolute;
    left: 0;
    top: 0;
    width: 1px;
    bottom: 0;
    border-left: 1px solid @c;
    color: @c;
    transform-origin: 0 0;
    transform: scaleX(0.5);
  }

  .setRightLine(@c: #C7C7C7) {
    content: " ";
    position: absolute;
    right: 0;
    top: 0;
    width: 1px;
    bottom: 0;
    border-right: 1px solid @c;
    color: @c;
    transform-origin: 100% 0;
    transform: scaleX(0.5);
  }
  .setLine(@c: #C7C7C7) {
    content: " ";
    position: absolute;
    left: 0;
    top: 0;
    width: 200%;
    border: 1px solid @c;
    color: @c;
    height: 200%;
    transform-origin: left top;
    transform: scale(0.5);
  }

  .vux-1px,
  .vux-1px-t,
  .vux-1px-b,
  .vux-1px-tb,
  .vux-1px-l,
  .vux-1px-r {
    position: relative;
  }

  .vux-1px {
    &:before {
      .setLine();
    }
  }

  .vux-1px-t {
    &:before {
      .setTopLine();
    }
  }

  .vux-1px-b {
    &:after {
      .setBottomLine();
    }
  }

  .vux-1px-tb {
    &:before {
      .setTopLine();
    }

    &:after {
      .setBottomLine();
    }
  }

  .vux-1px-l {
    &:before {
      .setLeftLine();
    }
  }

  .vux-1px-r {
    &:after {
      .setRightLine();
    }
  }
</style>

<style scoped>
  * {
    margin: 0;
    padding: 0;
    box-sizing: border-box; 
  }
  .cs-rule {
    position: relative;
    width: 100vw;
    height: calc(260 / 750 * 100vw);
    overflow: hidden;
    --pointer-color: rgb(97,206,81);
    --rule-width: 40;
    --num-size: 50
  }
  
  .cs-scrollrule {
    height: calc(200 / 750 * 100vw);
  }
  
  .cs-scrollrule-hook {
    list-style: none;
    overflow: hidden;
    border-collapse: collapse;
    white-space: nowrap;
    display: inline-block;
  }
  
  .cs-scroll-item {
    display: inline-block;
    width: calc(100vw / var(--rule-width));
    text-align: center;
    vertical-align: top;
  }
  
  /*刻度表数字*/
  .cs-scroll-item-num {
    width: calc(100 / 750 * 100vw);
    margin-left: calc(-50 / 750 * 100vw);
    margin-top: calc(38 / 750 * 100vw);
    text-align: center;
    font-size: calc(var(--num-size) / 750 * 100vw);
    color: #cccccc;
  }
  
  /*中间红色指针*/
  .cs-scroll-item-pointer {
    position: absolute;
    top: 0;
    left: 50%;
    height: calc(70 / 750 * 100vw);
    transform: translate(-50%, 0);
    border-right: 0.5vw solid var(--pointer-color);
  }
  
  .cs-scroll-item-rule {
    display: inline-block;
    width: calc(100vw / 40);
    box-sizing: border-box;
  }
  
  .vux-1px-l[data-v-db07d170]:before {
    border-color: #000000 !important;
  }
  
  .vux-1px-l:before {
    border-color: #000000 !important;
  }
  
  /*刻度1的*/
  .cs-scale-one {
    height: calc(30 / 750 * 100vw);
  }
  
  /*刻度0.5的*/
  .cs-scale-half {
    height: calc(44 / 750 * 100vw);
  }
  
  /*刻度10的*/
  .cs-scale-integer {
    height: calc(60 / 750 * 100vw);
  }
  
  /*0刻度前面的空白*/
  .cs-rule-null {
    margin-right: calc(-8 / 750 * 100vw);
    display: inline-block;
  }
  .cs-rule-null-after {
    margin-left: calc(-8 / 750 * 100vw);
    display: inline-block;
  }
</style>

 

 
 
posted @ 2022-11-04 16:31  球球啦啦啦  阅读(2888)  评论(0编辑  收藏  举报