类似于 时间选择器 组件

效果
在这里插入图片描述

<template>
  <div class="time-picker" id="time-picker" v-click-outside="handleClose">
      <Input
        :readonly="true"
        :value="backfillText"
        @click.native="handleOpen"
      >
        <i slot="prefix" class="iconfont icon-ico_date"></i>
      </Input>
      <div class="dropdown-con" v-show="visible">
        <div class="header-title">
          <span>开始</span>
          <span></span>
          <span>结束</span>
        </div>
        <div class="time-range-con" id="time-range-con">
          <ul id="range-con" class="range-con" ref="hours">
            <li
              v-for="(item, index) in hoursList"
              :key="index"
              :class="item.value === startTime ? 'active-cell' : ''"
              @click="handleClick(item)"  
            >
              {
    
    {
    
    formatTime(item.label)}}
            </li>
          </ul>
          <div>
            <i class="iconfont icon-ico_arrow"></i>
          </div>
          <ul id="range-con" class="range-con" ref="hoursEnd">
            <li
              v-for="(item,index) in hoursList"
              :key="index"
              :class="item.value === endTime ? 'active-cell' : ''"
              @click="handleClickEnd(item)"
            >
            {
    
    {
    
    formatTime(item.label)}}
            </li>
          </ul>
        </div>
      </div>
  </div>
</template>

<script>
import moment from 'moment';

let hoursList = [];
for(let i = 0; i <=24; i++) {
    
    
  hoursList.push({
    
    
    label: i,
    value: i
  });
}

export default {
    
    
  name: 'timePicker',

  props: {
    
    
    value: {
    
    
      type: Array,
      default: () => ['0:00','24:00']
    }
  },

  data() {
    
    
    return {
    
    
      visible: false,
      hoursList: hoursList,
      startTime: '',
      endTime: ''
    };
  },

  created() {
    
    },

  computed: {
    
    
    backfillText() {
    
    
      let dates = [];
      dates[0] = `${
      
      this.formatTime(this.startTime)}:00`;
      dates[1] = `${
      
      this.formatTime(this.endTime)}:00`;
      this.$emit('input', dates);
      return `${
      
      this.formatTime(this.startTime)}:00 - ${
      
      this.formatTime(this.endTime)}:00`;
    }
  },

  watch: {
    
    
    value: {
    
    
      handler(newVal, oldVal) {
    
    
        const [startTime, endTime] = newVal.slice();
        this.startTime = Number(startTime.split(':')[0]) || 0;
        this.endTime = Number(endTime.split(':')[0]) || 0;
      },
      immediate: true,
    },

    startTime(newVal, oldVal) {
    
    
      this.scroll('hours', newVal, oldVal);
    },

    endTime(newVal, oldVal) {
    
    
      this.scroll('hoursEnd',newVal, oldVal);
    }
  },

  methods: {
    
    
    scroll(type, newVal, oldVal) {
    
    
      const from = oldVal * 20;  //每个时间的高度20px
      const to = newVal * 20;
      this.$nextTick(() => {
    
    
        this.scrollTop(this.$refs[type], from, to);
      })
    },

    /**
     * 点击或该开始进入 内容出现在第一个
     */
    scrollTop(el, from = 0, to, duration = 500, endCallback) {
    
    
      if (!window.requestAnimationFrame) {
    
    
        window.requestAnimationFrame =
          window.webkitRequestAnimationFrame ||
          function(callback) {
    
    
            return window.setTimeout(callback, 1000 / 60);
          };
      }
      const difference = Math.abs(from - to);
      const step = Math.ceil((difference / duration) * 50);

      function scroll(start, end, step) {
    
    
        if (start === end) {
    
    
          endCallback && endCallback();
          return;
        }

        let d = start + step > end ? end : start + step;
        if (start > end) {
    
    
          d = start - step < end ? end : start - step;
        }

        if (el === window) {
    
    
          window.scrollTo(d, d);
        } else {
    
    
          el.scrollTop = d;
        }
        window.requestAnimationFrame(() => scroll(d, end, step));
      }
      scroll(from, to, step);
    },

    /**
     * 打开 选择时间
     */
    handleOpen() {
    
    
      this.visible = true;
      this.scroll('hours', this.startTime, 0);
      this.scroll('hoursEnd', this.endTime, 0);
    },

    /**
     * 0补齐
     */
    formatTime(text) {
    
    
      return text < 10 ? '0' + text : text;
    },

    /**
     * 点击旁边的内容 弹窗关闭
     */
    handleClose() {
    
    
      this.visible = false;
    },

    /**
     * 选择开始时间
     */
    handleClick(item) {
    
    
      this.startTime = item.value;
      if(!this.endTime || this.endTime < this.startTime) {
    
    
        this.endTime = this.startTime;
      }
    },

    /**
     * 选择结束时间
     */
    handleClickEnd(item) {
    
    
      if(item.value < this.startTime) {
    
    
        return;
      }
      this.endTime = item.value;
    }
  },
};
</script>

<style scoped lang="scss">
/*其它所有滚动条样式*/
#range-con::-webkit-scrollbar {
    
    
  /*滚动条整体样式*/
  width: 4px;
  /*高宽分别对应横竖滚动条的尺寸*/
  height: 0;
}
#range-con::-webkit-scrollbar-thumb {
    
    
  /*滚动条里面小方块*/
  border-radius: 2px;
  background: rgba(191, 191, 191, 1);
}
#range-con::-webkit-scrollbar-track {
    
    
  /*滚动条里面轨道*/
  border-radius: 0;
  background: #fff;
}

.time-picker {
    
    
  position: relative;
}

.dropdown-con {
    
    
  width: 190px;
  max-height: 200px;
  overflow: auto;
  z-index: 100;
  margin: 5px 0;
  position: absolute;
  background-color: #fff;
  border-radius: 4px;
  -webkit-box-shadow: 0 1px 6px rgba(0, 0, 0, 0.2);
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.2);
  .header-title {
    
    
    display: flex;
    padding: 13px;
    font-size: 12px;
    border-bottom: 1px solid #e8eaec;
    & > span {
    
    
      flex: 1;
      text-align: left;
    }
  }
}

.time-range-con {
    
    
  display: flex;
  position: relative;
  &::after {
    
    
    content: '';
    display: block;
    position: absolute;
    background: #e8eaec;
    width: 4px;
    transform: translateX(-50%);
    top: 0px;
    bottom: 0px;
  }
  & > ul {
    
    
    height: 150px;
    flex: 2;
    overflow-y: hidden;
    &:hover {
    
    
      overflow-y: auto;
    }
    & > li {
    
    
      font-size: 12px;
      padding-left: 15px;
      height: 20px;
      line-height: 20px;
      cursor: pointer;
      &:hover {
    
    
        color: #f90;
        background: #f3f3f3;
      }
    }
  }
  & > div {
    
    
    flex: 1;
    // justify-content: center;
    // align-items: center;
    text-align: center;
    padding-top: 50px;
    border-left: 1px solid #e3e3e3;
    border-right: 1px solid #e3e3e3;
  }
  .active-cell {
    
    
    color: #f90;
    background: #f3f3f3;
  }
}
</style>

引用

<time-picker class="mar-left" v-model="hourValue"></time-picker>

hourValue: ['09:00','23:00'],

猜你喜欢

转载自blog.csdn.net/weixin_43843679/article/details/121382819