用Element-Plus实现一个日期组件,日期选项均为5的倍数

359 阅读3分钟

背景

由于最近的项目是做一个关于电量、电费读取抄表数据的一个任务。有一个逻辑是电量每5分钟会获取一次。所以选择用Elementui-Plus的 el-date-picker 实现。type="datetime",分钟数据只有0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55这几个值

但是 Element-Plus 提供的组件不支持直接配置可选择的项的值。

组件实现

实际期待的效果,期望分钟的选项是0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55这些数据。

image.png

方案一

实现思路:将非[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55]这些数据的项都隐藏掉。实现时机:在打开日期选择器的弹框时,就修改下拉项。

image.png

image.png 代码:

const visibleChange = (openVisible)=> {
  console.log('时间选择器',datetimeRef.value)
  // document.addEventListener('focus', handleGlobalFocus, false);
  var elements = document.querySelectorAll(".el-input__inner");
  for (var i = 0; i < elements.length; i++) {
    elements[i].addEventListener("focus", function () {
      let resultNode = document.querySelectorAll(
        ".el-scrollbar__view.el-time-spinner__list"
      );
      for (let j = 0; j < resultNode.length; j++) {
        let item_j = resultNode[j];
        if (item_j.childNodes.length == 64) {
          for (let k = 0; k < item_j.childNodes.length; k++) {
            let item_k = item_j.childNodes[k];
            if (item_k.innerHTML && Number(item_k.innerHTML) % 5 != 0) {
              item_k.style.display = "none";
            }
          }
        }
      }
    });
  }
}

这个能实现5分钟的项,但是滚动就会出现问题。滚动不会实时展示对应的5分钟数值。而是从0开始的有序数字。有瑕疵的方案之一。

image.png

方案二

同方案一一样思路,只不过变成从disabled-minutes出发控制数据。

image.png

image.png

const datetimeRef = ref(null)
const visibleChange = (openVisible)=> {
  console.log('时间选择器',datetimeRef.value)
  document.addEventListener('focus', handleGlobalFocus, false);
}

const disabledMinutes = () => {
  handleInvalidMinutes()
  return Array.from({ length: 12 },(v,k) =>k ).filter( minutes =>  ![0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55].includes(minutes))
}

const handleInvalidMinutes = () => {
  nextTick(() => {
    const minuteItems = document.querySelectorAll(".el-time-panel .el-time-spinner__wrapper:nth-child(2n) .el-time-spinner__item");
    minuteItems.forEach(item => {
      const minute = parseInt(item.textContent, 10) 
      if(![0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55].includes(minute)) {
        item.classList.add('is-disabled')
        item.style.display = 'none'
      } else {
        item.classList.remove('is-disabled')
        item.style.display = ''
      }
    })
  })
}

const handleGlobalFocus = (event) => {
  const target = event.target;
  if (target && target.closest('.el-date-range-picker__time-picker-wrap:nth-child(2n) .el-input__inner')) {
    handleInvalidMinutes();
  }
};

这个方案也能实现效果。同样来验证一下滚动选中的效果,返现滚动条虽然内有数据展示在输入框的错误瑕疵,但是会出现0,5,15等数据选中在下拉中没有选中效果,输入框正常的瑕疵,滚动条有点不受控。

image.png

方案三-完美解决方案

业务方案一:让产品出一个选择YYYY-MM-dd日期后,在选择一次分钟的数据的框,利用 el-date-picker 和 el-time-picker 组合实现。 业务方案二: 换一种设计形式。

image.png

方案四 -非5分钟的数据禁用,滚动自动定位到5的倍数的选项

image.png

源码实现

<template>
...
 <div class="filter-item">
    <span class="filter-label">抄表时间:</span>
    <el-date-picker
      v-model="meterReadingDate"
      type="datetime"
      placeholder="选择日期时间"
      format="YYYY-MM-DD HH:mm"
      value-format="YYYY-MM-DD HH:mm"
      :clearable="true"
      :default-time="defaultTime"
      :disabledMinutes="disabledMinutes"
      :hideDisabledOptions="true"
      @change="handleDateTimeChange"
    />
    <el-button type="primary" @click="applyFilter">应用筛选</el-button>
  </div>
  ...
</template>

<script>
...
// 抄表时间筛选
const meterReadingDate = ref('')
const defaultTime = new Date(2000, 1, 1, 0, 0, 0) // 默认时间 00:05

// 禁用不在选项中的分钟
const disabledMinutes = () => {
  const allowedMinutes = [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55]
  const disabled = []
  for (let i = 0; i < 60; i++) {
    if (!allowedMinutes.includes(i)) {
      disabled.push(i)
    }
  }
  return disabled
}

// 处理日期时间变化
const handleDateTimeChange = (val: string) => {
  console.log('日期时间变化:', val)
}

...
</script>

总结

组件原生不支持的方式,可以考虑利用现有支持的方案替换,具体还根据业务自行实现。建议参考方案四。

该文章仅用于学习记录,不涉及商业传播。