Loading

基于mpvue实现微信小程序区间选择(range-slider)

微信小程序实现区间选择,时间范围选择,可设置步长

API

slider props
参数 必选 类型 默认值 说明
disabled false Boolean false 是否禁用
max false Number 24 最大值
min false Number 0 最小值
value false Number 0 默认值
step false Number 0.5 步长
type false String time 组件类型

组件截图

Talk is cheap. Show me the code

<template>
   <div class="range-slider" @click="onClick">
     <div class="range-slider-wrap">
       <div class="range-slider-bar" :style="atTrackStyle"></div>
       <div class="range-slider-button" @touchmove="onTouchMove($event,'aX')" @touchend="onTouchEnd($event, 'aX')" @touchcancel="onTouchEnd" :style="{left: aX + '%'}">
         <div class="range-slider-value">{{range[0]}}</div>
       </div>
       <div class="range-slider-button" @touchmove="onTouchMove($event,'bX')" @touchend="onTouchEnd($event, 'bX')" @touchcancel="onTouchEnd" :style="{left: bX + '%'}">
         <div class="range-slider-value">{{range[1]}}</div>
       </div>
     </div>
   </div>
</template>
<script>
export default {
    props: {
        disabled: {
            type: Boolean,
            default: false
        },
        max: {
            type: Number,
            default: 24
        },
        min: {
            type: Number,
            default: 0
        },
        step: {
            type: Number,
            default: 0.5
        },
        value: {
            type: Array,
            default: () => [0, 0]
        },
        type: {
            type: String,
            default: 'time'
        }
    },
    data () {
        return {
            aX: 0,
            bX: 0,
            width: 0, // range宽度
            left: 0, // range 到屏幕左边的距离
            deltaValue: this.max - this.min,
            currentSlider: '',
            currentValue: [0, 0]
        };
    },
    computed: {
        atTrackStyle () {
            const { aX, bX } = this;
            const smallerX = Math.min(aX, bX);
            const deltaX = Math.abs(aX - bX);
            return `left:${smallerX}%;width:${deltaX}%`;
        },
        range () {
            let range = this.currentValue;
            return this.type === 'time' ? range.map(item => this.formatHoursToUT(item)) : range;
        }
    },
    methods: {
        onTouchMove (event, sliderName) {
            event = event.mp;
            if (this.disabled) { return; }
            const clientX = event.touches[0].clientX;
            this.setSliderValue(sliderName, clientX - this.left, 'onChange');
        },
        onTouchEnd (sliderName) {
            if (this.disabled) { return; }
            this.currentSlider = sliderName;
            this.triggerEvent('onAfterChange');
        },
        setSliderValue (sliderName, targetValue, funcName) {
            const distance = Math.min(Math.max(targetValue, 0), this.width);
            const sliderValue = Math.floor((distance / this.width) * 100);
            if (funcName) {
                this.triggerEvent(funcName);
            }
            if (sliderName === 'bX' && sliderValue <= this.aX) {
                this[sliderName] = this.aX;
                return;
            }
            if (sliderName === 'aX' && sliderValue >= this.bX) {
                this[sliderName] = this.bX;
                return;
            }
            this[sliderName] = sliderValue;
        },
        triggerEvent (funcName) {
            const { aX, bX } = this;
            const steps = Math.round(this.deltaValue / this.step);
            const a = Math.round((aX / 100) * steps) * this.step + this.min;
            const b = Math.round((bX / 100) * steps) * this.step + this.min;
            const result = [a, b].sort((x, y) => x - y);
            console.log(aX, bX, result, '位移');
            this.currentValue = result;
            this.$emit(funcName, result);
        },
        onClick (event) {
            if (this.currentSlider && !this.disabled) {
                let sliderValue = 0;
                const detail = event.touches[0].clientX;
                sliderValue = detail - this.left;
                this.setSliderValue(this.currentSlider, sliderValue, 'onChange');
            }
        },
        setValue (value) {
            this.aX = Math.round(((value[0] - this.min) / this.deltaValue) * 100);
            this.bX = Math.round(((value[1] - this.min) / this.deltaValue) * 100);
        },
        formatHoursToUT (value) {
            value = value * 3600;
            let result = parseInt(value);
            let h = Math.floor(result / 3600) < 10 ? '0' + Math.floor(result / 3600) : Math.floor(result / 3600);
            let m = Math.floor((result / 60 % 60)) < 10 ? '0' + Math.floor((result / 60 % 60)) : Math.floor((result / 60 % 60));
            result = `${h}:${m}`;
            return result;
        },
        getRect (selector, all) {
            return new Promise(resolve => {
                wx.createSelectorQuery()[all ? 'selectAll' : 'select'](selector)
                    .boundingClientRect(rect => {
                        if (all && Array.isArray(rect) && rect.length) {
                            resolve(rect);
                        }
                        if (!all && rect) {
                            resolve(rect);
                        }
                    })
                    .exec();
            });
        }
    },
    mounted () {
        const { value } = this;
        this.getRect('.range-slider')
            .then(rect => {
                console.log(rect, value);
                this.width = Math.round(rect.width);
                this.left = Math.round(rect.left);
                this.setValue(value);
            });
    }
};
</script>
<style lang="less">
.range-slider {
  width: 80%;
  margin-left: 10%;
  .range-slider-wrap {
    position:relative;
    background-color:#EFEFEF;
    width: 100%;
    height: 12rpx;
    border-radius: 8rpx;
    margin: 50rpx 0;
    vertical-align: middle;
    cursor: pointer;
  }
  .range-slider-bar {
    position:absolute;
    background-color:#FBBB00;
    height: 12rpx;
  }
  .range-slider-button {
    position:absolute;
    top:50%;
    transform:translate3d(-50%,-50%,0);
    width: 40rpx;
    height: 40rpx;
    background-color:#fff;
    border: 4rpx solid #DDDDDD;
    box-shadow: 0 2rpx 8rpx 0 rgba(211,211,211,0.68);
    border-radius: 20rpx;
    & .range-slider-value {
      position: absolute;
      top: -70rpx;
      left: 50%;
      transform: translateX(-50%);
      font-size: 40rpx;
      color: #9EA4A1;
    }
  }
}
</style>



posted @ 2019-09-19 16:28  lewiskycc  阅读(850)  评论(0编辑  收藏  举报