基于elementUI自定義時間組件

實現(xiàn)如下可以自定義時間選項的時間組件母赵。


image.png
<CustomTimePicker
                    v-model="movie.playTime"
                    :defaultTime="defaultTime"
                    :prevTime="prevTime"
                    :duration="duration"
                    @cacul="getTime(s_index, m_index, movie)"
                  ></CustomTimePicker>
<template>
<!-- 這是個很不成熟的組件垃僚,一次性組件瞬女,用完即拋 -->
<!-- 這是個很不成熟的組件川背,一次性組件,用完即拋 -->
<!-- 這是個很不成熟的組件暮顺,一次性組件隆箩,用完即拋 -->
<div class="custom-timer-picker-container">
  <div @click.stop="showTimeFun()" style="position: relative;">
    <el-input
      placeholder="請選擇時間"
      :value="value"
      @mouseenter.native="handleMouseEnter()"
      @mouseleave.native="handleMouseLeave()"
    >
      <i slot="prefix" class="el-input__icon el-icon-time"></i>
      <i slot="suffix"
        class="el-input__icon"
        @click.stop="handleClickIcon()"
        :class="[showClose ? '' + 'el-icon-circle-close' : '']">
      </i>
    </el-input>
  </div>
  <div class="custom-timer-picker" v-clickoutside="handleClose" :style="{ visibility: pickerVisible ? 'visible' : 'hidden' }">
    <transition name="el-zoom-in-top" @after-leave="$emit('dodestroy')">
      <div class="el-time-panel">
        <div class="el-time-panel__content">
          <div class="time-box">
            <!-- 時 -->
            <el-scrollbar
              @mousemove.native="adjustCurrentSpinner('hours')"
              class="el-time-spinner__wrapper"
              wrap-style="max-height: inherit;"
              view-class="el-time-spinner__list"
              noresize
              tag="ul"
              ref="hours">
              <li
                @click.stop="handleClick('hours', { value: item.hour, index: index, disabled: item.disabled })"
                v-for="(item, index) in hourList"
                :key="item.hour"
                class="el-time-spinner__item"
                :class="{ 'active': item.hour === hours, 'disabled': item.disabled }"
              >
                {{ item.hour }}
              </li>
            </el-scrollbar>
            <!-- 分 -->
            <el-scrollbar
              @mousemove.native="adjustCurrentSpinner('minutes')"
              class="el-time-spinner__wrapper"
              wrap-style="max-height: inherit;"
              view-class="el-time-spinner__list"
              noresize
              tag="ul"
              ref="minutes">
              <li
                @click.stop="handleClick('minutes', { value: item.minute, index: index, disabled: item.disabled })"
                v-for="(item, index) in minuteList"
                :key="item.minute"
                class="el-time-spinner__item"
                :class="{ 'active': item.minute === minutes, 'disabled': item.disabled }"
              >
                {{ item.minute }}
              </li>
            </el-scrollbar>
            <!-- 秒 -->
            <el-scrollbar
              @mousemove.native="adjustCurrentSpinner('seconds')"
              class="el-time-spinner__wrapper"
              wrap-style="max-height: inherit;"
              view-class="el-time-spinner__list"
              noresize
              tag="ul"
              ref="seconds">
              <li
                @click.stop="handleClick('seconds', { value: item.second, index: index, disabled: item.disabled })"
                v-for="(item, index) in secondList"
                :key="item.second"
                class="el-time-spinner__item"
                :class="{ 'active': item.second === seconds, 'disabled': item.disabled }"
              >
                {{ item.second }}
              </li>
            </el-scrollbar>
          </div>
        </div>
        <div class="el-time-panel__footer">
          <button
            type="button"
            class="el-time-panel__btn cancel"
            @click.stop="handleCancel">取消</button>
          <button
            type="button"
            class="el-time-panel__btn confirm"
            @click.stop="handleConfirm()">確定</button>
        </div>
      </div>
    </transition>
  </div>
</div>
</template>
<script>
import Clickoutside from 'element-ui/src/utils/clickoutside';
export default {
  props: {
    // defaultTime用于設置當前時間控件的默認時間,點擊取消按鈕或者選擇了 disabled 的時間的場景使用
    defaultTime: {
      type: String,
      default () {
        return ''
      }
    },
    // prevTime表示前一個設置的最大播放時間琼梆,配合 duration 用于計算當前時間控件可選的最早時間
    prevTime: {
      type: String,
      default () {
        return ''
      }
    },
    // duration表示前一個設置最大播放時間的影片的播放時長性誉,配合 prevTime 用于計算當前時間控件可選的最早時間
    duration: {
      type: Number,
      default () {
        return 0
      }
    },
    // 當前時間控件的時間
    value: null
  },
  directives: {
    Clickoutside
  },
  data() {
    return {
      pickerVisible: false,
      showClose: false,
      hours: '',
      minutes: '',
      seconds: '',
      limitTime: '06:00:00',
      hourList: [
        {
          hour: '06',
          disabled: false
        },
        {
          hour: '07',
          disabled: false
        },
        {
          hour: '08',
          disabled: false
        },
        {
          hour: '09',
          disabled: false
        },
        {
          hour: '10',
          disabled: false
        },
        {
          hour: '11',
          disabled: false
        },
        {
          hour: '12',
          disabled: false
        },
        {
          hour: '13',
          disabled: false
        },
        {
          hour: '14',
          disabled: false
        },
        {
          hour: '15',
          disabled: false
        },
        {
          hour: '16',
          disabled: false
        },
        {
          hour: '17',
          disabled: false
        },
        {
          hour: '18',
          disabled: false
        },
        {
          hour: '19',
          disabled: false
        },
        {
          hour: '20',
          disabled: false
        },
        {
          hour: '21',
          disabled: false
        },
        {
          hour: '22',
          disabled: false
        },
        {
          hour: '23',
          disabled: false
        }
      ],
      minuteList: [
        {
          minute: '00',
          disabled: false
        },
        {
          minute: '15',
          disabled: false
        },
        {
          minute: '30',
          disabled: false
        },
        {
          minute: '45',
          disabled: false
        },
        {
          minute: '59',
          disabled: false
        }
      ],
      secondList: [
        {
          second: '00',
          disabled: false
        },
        {
          second: '59',
          disabled: false
        }
      ]
    }
  },
  watch: {
    'pickerVisible'(val) {
      if(val) {
        this.init_hours_minutes_seconds()
        this.$nextTick(()=>{ //這是必要的,不然秒級的59選項選不上
          this.adjustSpinners()
          this.initHourDisableItem()
          this.initMinuteDisableItem()
        })
      }
    },
    'hours'(newVal) {
      if(newVal == '23') {
        if(!this.minuteList.some(item => item.minute == '59')) {
          this.minuteList.push({minute: '59', disabled: false})
        }
      } else {
        if(this.minuteList.some(item => item.minute == '59')) {
          this.minuteList.pop()
          if(this.minutes == '59') {
            this.minutes = this.minuteList[this.minuteList.length - 1].minute
            this.adjustSpinners()
          }
        }
      }
      this.initMinuteDisableItem()
      // 在可選范圍區(qū)域茎杂,則emit
      if(this.checkStatus()) {
        let time = `${this.hours}:${this.minutes}:${this.seconds}`
        this.pickVal(time, true)
      }
    },
    'minutes'(newVal) {
      if(newVal == '59') {
        if(!this.secondList.some(item => item.second == '59')) {
          this.secondList.push({second: '59', disabled: false})
        }
      } else {
        if(this.secondList.some(item => item.second == '59')) {
          this.secondList.pop()
          if(this.seconds == '59') {
            this.seconds = this.secondList[this.secondList.length - 1].second
            this.adjustSpinners()
          }
        }
      }
      this.initHourDisableItem()
      // 在可選范圍區(qū)域错览,則emit
      if(this.checkStatus()) {
        let time = `${this.hours}:${this.minutes}:${this.seconds}`
        this.pickVal(time, true)
      }
    },
    'seconds'() {
      // 在可選范圍區(qū)域,則emit
      if(this.checkStatus()) {
        let time = `${this.hours}:${this.minutes}:${this.seconds}`
        this.pickVal(time, true)
      }
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.bindScrollEvent();
    });
  },
  methods: {
    showTimeFun() {
      // 調(diào)用 cacul 方法先獲取 defaultTime蛉顽、prevTime蝗砾、duration
      this.$emit('cacul')
      setTimeout(() => {
        this.pickerVisible = true
      })
    },
    handleClose () {
      this.pickerVisible = false
    },
    handleMouseEnter() {
      if(this.value) {
        this.showClose = true
      }
    },
    handleMouseLeave() {
      this.showClose = false
    },
    handleClickIcon() {
      this.pickVal('', true)
    },
    generateTimeList(delta) {
      let f = n => `${n}`.padStart(2, '0')
      let result = [], date = new Date()
      date.setHours(6)
      date.setMinutes(delta)
      let day = date.getDate()
      while (date.getDate() === day) {
        let h = date.getHours()
        let m = date.getMinutes()
        result.push(`${f(h)}:${f(m)}:00`)
        date.setMinutes(m + delta)
      }
      result = ['06:00:00', ...result, '23:59:59']
      return result
    },
    getLimitTimeToSeconds() {
      let sum = 0
      sum += this.$moment.duration(this.prevTime).as('seconds'); // 上一部電影播放時間轉化成秒
      sum += this.duration // 加上上一部電影的播放時長
      if(this.prevTime || this.duration) {
        sum += 8 * 60 // 先加上8分鐘(這是最早能選擇的時間)
      }
      if(this.prevTime) {
        sum -= 6 * 60 * 60 // 因為從6點開始選擇時間,所以減去6個小時的秒數(shù)
      }
      return sum
    },
    getLimitTime() {
      let timeToseconds = this.getLimitTimeToSeconds()
      let time = ''
      let timeArr = this.generateTimeList(15)
      for(let i = 0; i < timeArr.length; i++) {
        let totalTime = this.$moment.duration(timeArr[i]).as('seconds') - 6 * 60 * 60 // 需要減去6個小時
        if(totalTime > timeToseconds) { // 找到第一個能選擇的時間
          time = timeArr[i]
          break
        }
      }
      return time
    },
    init_hours_minutes_seconds() {
      // 如果當前時間空間選擇了時間的話携冤,并且為可選時間悼粮,那么初始化為已選擇的時間
      // 如果沒有選擇時間,那么使用上一個時間控件選擇的時間加上時長轉化過來的時分秒加上8分鐘
      // 如果上個控件沒有時間曾棕,也沒有時長扣猫,那么使用 06:00:00
      let isBeyond = false
      if(this.prevTime) {
        isBeyond = this.$moment.duration(this.prevTime).as('seconds') + this.duration + 8*60 > this.$moment.duration(this.defaultTime).as('seconds')
      } else if(this.duration) {
        isBeyond = this.duration + 8*60 + 6*60*60 > this.$moment.duration(this.defaultTime).as('seconds')
      }
      if (isBeyond) {
        let time = this.getLimitTime()
        if(time) {
          this.limitTime = time // 這是最早能選擇的可選項時間
          let arr = time.split(':')
          this.hours = arr[0]
          this.minutes = arr[1]
          this.seconds = arr[2]
        } else {
          // 找不到時間了 證明已經(jīng)排滿時間了 則全部置灰
          this.hours = '23'
          this.minutes = '59'
          this.seconds = '59'
        }
        return false
      }
      if (this.defaultTime) {
        let arr = this.defaultTime.split(':')
        this.hours = arr[0]
        this.minutes = arr[1]
        this.seconds = arr[2]
        return false
      }
      if (this.value) {
        let arr = this.value.split(':')
        this.hours = arr[0]
        this.minutes = arr[1]
        this.seconds = arr[2]
        return false
      }
      this.hours = '06'
      this.minutes = '00'
      this.seconds = '00'
    },
    bindScrollEvent() {
      const bindFuntion = (type) => {
        this.$refs[type].wrap.onscroll = (e) => {
          this.handleScroll(type, e);
        };
      };
      bindFuntion('hours');
      bindFuntion('minutes');
      bindFuntion('seconds');
    },
    handleScroll(type) {
      let a = this.$refs[type].wrap.scrollTop
      let b = this.scrollBarHeight(type) * 0.5 - 10
      let c = this.typeItemHeight(type)
      let d = type === 'hours' ? this.hourList.length - 1 : type === 'minutes' ? this.minuteList.length - 1 : this.secondList.length - 1
      const index = Math.min(Math.round((a - b / c + 3) / c), d);
      this.modifyDateField(type, index);
    },
    modifyDateField(type, index, value) {
      switch (type) {
        case 'hours': 
          this.hours = this.hourList[index].hour;
          break
        case 'minutes':
          this.minutes = this.minuteList[index].minute;
          break
        case 'seconds':
          this.seconds = this.secondList[index].second;
          break
      }
    },
    checkStatus() {
      let hourArr = this.hourList.filter(item => item.hour == this.hours)
      let minuteArr = this.minuteList.filter(item => item.minute == this.minutes)
      let secondArr = this.secondList.filter(item => item.second == this.seconds)
      return !hourArr[0].disabled && !minuteArr[0].disabled && !secondArr[0].disabled
    },
    scrollBarHeight(type) {
      return this.$refs[type].$el.offsetHeight;
    },
    typeItemHeight(type) {
      return this.$refs[type].$el.querySelector('li').offsetHeight;
    },
    getLiIndex(type, value) {
      let index = 0
      if(type == 'hours') index = this.hourList.findIndex(item => item.hour == value)
      if(type == 'minutes') index = this.minuteList.findIndex(item => item.minute == value)
      if(type == 'seconds') index = this.secondList.findIndex(item => item.second == value)
      return index
    },
    handleClick(type, {value, index, disabled}) {
      if (!disabled) {
        this.modifyDateField(type, index, value);
        this.adjustSpinner(type, value);
      }
    },
    adjustCurrentSpinner(type) {
      this.adjustSpinner(type, this[type]);
    },
    adjustSpinners() {
      this.adjustSpinner('hours', this.hours);
      this.adjustSpinner('minutes', this.minutes);
      this.adjustSpinner('seconds', this.seconds);
    },
    adjustSpinner(type, value) {
      const el = this.$refs[type].wrap;
      if (el) {
        let index = this.getLiIndex(type, value)
        el.scrollTop = Math.max(0, index * this.typeItemHeight(type));
      }
    },
    handleConfirm() {
      if(this.checkStatus()) {
        let time = `${this.hours}:${this.minutes}:${this.seconds}`
        this.pickVal(time, false)
      } else {
        this.pickVal(this.defaultTime, false)
      }
    },
    handleCancel() {
      this.pickVal(this.defaultTime, false)
    },
    pickVal(time, visible) {
      if(!visible) {
        this.pickerVisible = false
      }
      this.$emit('input', time)
    },
    initHourDisableItem() {
      let currentTime = ''
      for(let i = 0; i < this.hourList.length; i++) {
        for(let j = 0; j < this.minuteList.length; j++) {
          if(this.minuteList[j].minute == this.minutes) {
            for(let k = 0; k < this.secondList.length; k++) {
              currentTime = `${this.hourList[i].hour}:${this.minuteList[j].minute}:${this.secondList[k].second}`
              let the_currentTime_seconds = this.$moment.duration(currentTime).as('seconds') - 6 * 60 * 60 // 需要減去6個小時;
              let the_earliest_limitTime_secondes = this.getLimitTimeToSeconds()
              if(the_currentTime_seconds < the_earliest_limitTime_secondes) {
                this.hourList[i].disabled = true
                this.secondList[k].disabled = true
              } else {
                this.hourList[i].disabled = false
                this.secondList[k].disabled = false
              }
              if(the_currentTime_seconds >= 24 * 60 * 60) {
                this.hourList[i].disabled = true
                this.secondList[k].disabled = true
              }
            }
            break
          }
        }
      }
    },
    initMinuteDisableItem() {
      let currentTime = ''
      for(let i = 0; i < this.hourList.length; i++) {
        if(this.hourList[i].hour == this.hours) {
          for(let j = 0; j < this.minuteList.length; j++) {
            for(let k = 0; k < this.secondList.length; k++) {
              currentTime = `${this.hourList[i].hour}:${this.minuteList[j].minute}:${this.secondList[k].second}`
              let the_currentTime_seconds = this.$moment.duration(currentTime).as('seconds') - 6 * 60 * 60 // 需要減去6個小時;
              let the_earliest_limitTime_secondes = this.getLimitTimeToSeconds()
              if(the_currentTime_seconds < the_earliest_limitTime_secondes) {
                this.minuteList[j].disabled = true
                this.secondList[k].disabled = true
              } else {
                this.minuteList[j].disabled = false
                this.secondList[k].disabled = false
              }
              if(the_currentTime_seconds >= 24 * 60 * 60) {
                this.minuteList[j].disabled = true
                this.secondList[k].disabled = true
              }
            }
          }
          break
        }
      }
    }
  }
}
</script>
<style lang="stylus" scoped>
.el-time-spinner__wrapper {
  width: 33.3%;
}
</style>
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市翘地,隨后出現(xiàn)的幾起案子申尤,更是在濱河造成了極大的恐慌癌幕,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件昧穿,死亡現(xiàn)場離奇詭異勺远,居然都是意外死亡,警方通過查閱死者的電腦和手機时鸵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門胶逢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人饰潜,你說我怎么就攤上這事初坠。” “怎么了彭雾?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵碟刺,是天一觀的道長。 經(jīng)常有香客問我薯酝,道長半沽,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任蜜托,我火速辦了婚禮抄囚,結果婚禮上,老公的妹妹穿的比我還像新娘橄务。我一直安慰自己幔托,他們只是感情好,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布蜂挪。 她就那樣靜靜地躺著重挑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪棠涮。 梳的紋絲不亂的頭發(fā)上谬哀,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機與錄音严肪,去河邊找鬼史煎。 笑死,一個胖子當著我的面吹牛驳糯,可吹牛的內(nèi)容都是我干的篇梭。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼酝枢,長吁一口氣:“原來是場噩夢啊……” “哼恬偷!你這毒婦竟也來了?” 一聲冷哼從身側響起帘睦,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤袍患,失蹤者是張志新(化名)和其女友劉穎坦康,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體诡延,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡滞欠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了肆良。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片仑撞。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖妖滔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情桶良,我是刑警寧澤座舍,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站陨帆,受9級特大地震影響曲秉,放射性物質發(fā)生泄漏。R本人自食惡果不足惜疲牵,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一承二、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧纲爸,春花似錦亥鸠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至颓哮,卻和暖如春家妆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背冕茅。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工伤极, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人姨伤。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓哨坪,卻偏偏與公主長得像,于是被迫代替她去往敵國和親姜挺。 傳聞我的和親對象是個殘疾皇子齿税,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容