elementUI中的el-date-picker日期月份时间选择器禁用选中当前和以后的日期

5,280 阅读1分钟

问题描述

时间选择器选择日期、月份在项目中比较常见,比如查询历史记录,我们需要选择具体日期或者发请求,获取历史数据。所以我们需要对时间选择器做一些控制,比如历史记录查询的话,就不能选择当前日期和以后的日期了。所以就需要把当前日期和未来日期给禁用掉,本文记录一下相应的代码写法。

使用饿了么UI肯定是要用官方给到的api,这里我们使用的是picker-options和disabledDate去控制,附上官方文档地址链接:element.eleme.cn/#/zh-CN/com…

禁用日期案例

效果图

1.png

代码如下

<template>
  <div id="app">
    <el-date-picker
      format="yyyy-MM-dd"
      value-format="yyyy-MM-dd"
      type="date"
      placeholder="请选择日期"
      v-model="dayDate"
      :picker-options="setDisabled"
    ></el-date-picker>
  </div>
</template>

<script>
export default {
  data() {
    return {
      timer: null,
      dayDate: "",
      setDisabled: {
        disabledDate(time) {
          return time.getTime() > Date.now();  // 可选历史天、可选当前天、不可选未来天
          // return time.getTime() > Date.now() - 8.64e7;  // 可选历史天、不可选当前天、不可选未来天
          // return time.getTime() < Date.now() - 8.64e7;  // 不可选历史天、可选当前天、可选未来天
          // return time.getTime() < Date.now(); // 不可选历史天、不可选当前天、可选未来天
        },
      },
    };
  },
  /*
    8.64e7 是科学计数法 8.64乘以10的7次方,即为86400000也就是 1000*60*60*24 也就是一天的毫秒数。因为Date.now()
    方法能够返回得到自1970年1月1日00:00:00(UTC)到当前时间的毫秒数。咱们是北京时间的时区,也就是为东8区,
    起点时间对应就是:"1970/01/01 08:00:00"

    picker-options需要一个最终的布尔值,所以是否减去8.64e7也就是是否往前推移一天,也就是是否包含当前的天数
  */
};
</script>

<style lang="less" scoped>
#app {
  width: 950px;
  height: 600px;
  box-sizing: border-box;
  margin: 50px;
}
</style>

禁用日期简单,下面我们说一下禁用月份,禁用月份需要对日期格式做一个转换并判断即可

禁用月份案例

效果图

2.png

代码如下

<template>
  <div id="app">
    <el-date-picker
      v-model="value"
      format="yyyy-MM"
      value-format="yyyy-MM"
      type="month"
      placeholder="请选择月份"
      :picker-options="setMonthDisabled"
    >
    </el-date-picker>
  </div>
</template>

<script>
export default {
  data() {
    return {
      value: "",
      setMonthDisabled: {
        disabledDate(time) {
          // 获取当前的月份信息
          const date = new Date(); // 获取当前的时间基本信息,值是这样的: Tue Jul 20 2021 14:59:43 GMT+0800 (中国标准时间)
          const year = date.getFullYear(); // 获取当前年份,值是这样的: 2021
          let month = date.getMonth() + 1; // 获取当前月份,值是这样的: 6   getMonth()方法返回值是0-11,也就是1月份到12月份,所以要加上1,才是当前月份
          if (month >= 1 && month <= 9) {
            // 如果是1月到9月就要在前面补上一个0   比如:02、07    月份这样表示
            month = "0" + month;
          }
          const nowDate = year.toString() + month.toString(); // 转换成字符串拼接,最终得到年和月,比如此时的时间是2021年7月20号,所以nowDate的值是:202107

          // 获取时间选择器的月份信息
          const timeyear = time.getFullYear(); // 获取时间选择器的年份(有很多)
          let timemonth = time.getMonth() + 1; // 与上面同理
          if (timemonth >= 1 && timemonth <= 9) {
            timemonth = "0" + timemonth;
          }
          const elTimeData = timeyear.toString() + timemonth.toString();

          // 返回,时间选择器的日期月份大于当前日期的月份,又因为disabledDate函数是控制月份禁用不可选
          // 所以,最终就是:时间选择器的月份大于当前的月份,就都禁用掉,所以就实现了最终效果:
          // 大于等于当前月份都不可选 
          return elTimeData <= nowDate; // 这里虽然是字符串,但是弱类型语言js会做一个转换,是可以比较大小的如: '202107' > '202008'
        },
      },
    };
  },
  methods: {},
};
</script>

<style lang="less" scoped>
#app {
  width: 950px;
  height: 600px;
  box-sizing: border-box;
  margin: 50px;
}
</style>

前后各一年

<template>
  <div id="box">
    <el-date-picker
      format="yyyy-MM"
      value-format="yyyy-MM"
      v-model="value"
      type="month"
      placeholder="选择月"
      :picker-options="setMonthDisabled"
    >
    </el-date-picker>
  </div>
</template>

<script>
export default {
  data() {
    return {
      value: "",
      setMonthDisabled: {
        disabledDate(time) {
          // 获取当前的月份信息
          const date = new Date(); 
          const year = date.getFullYear(); 
          let month = date.getMonth() + 1; 
          if (month >= 1 && month <= 9) {
            month = "0" + month;
          }
          const minNowDate = (year-1).toString() + month.toString(); // 获取当前时间往前推算一年的月份
          const maxNowDate = (year+1).toString() + month.toString(); // 获取当前时间往后推算一年的月份

          // 获取时间选择器的月份信息
          const timeyear = time.getFullYear(); 
          let timemonth = time.getMonth() + 1; 
          if (timemonth >= 1 && timemonth <= 9) {
            timemonth = "0" + timemonth;
          }
          const elTimeData = timeyear.toString() + timemonth.toString();

          // 把时间选择器小于最小的禁掉,大于最大的也禁用掉,这样的话就只能选择以当前时间点为原点,前后各一年的范围啦
          return  elTimeData < minNowDate | elTimeData > maxNowDate
        },
      },
    };
  },
};
</script>

<style lang="less" scoped>
#box {
  width: 100%;
  height: 600px;
  box-sizing: border-box;
  padding: 50px;
}
</style>

其实写法也是多样的,欢迎大家共同交流学习,共同进步

补充~月份面板里的中文月份替换成数字月份

道友说,把月份面板中的中文月份替换成数字月份,解法有两种:

  1. 修改源码
  2. 障眼法替换dom的innerHtml

笔者的解法是第二种,毕竟方便一些,如下:

效果图

中文月份替换数字月份.gif

代码

请看代码和注释

<template>
  <div class="wrap">
    <el-date-picker
      @focus="focusFn"
      v-model="value"
      type="month"
      placeholder="选择月"
    >
    </el-date-picker>
  </div>
</template>

<script>
// 6. 对象字典匹配形式,或者使用switch case也行
function chineseToNum(month) {
  let monthObj = {
    一月: "1月",
    二月: "2月",
    三月: "3月",
    四月: "4月",
    五月: "5月",
    六月: "6月",
    七月: "7月",
    八月: "8月",
    九月: "9月",
    十月: "10月",
    十一月: "11月",
    十二月: "12月",
  };
  // 7. 将中文月份更改为数字月份
  return monthObj[month];
}
let numMonthArr = [
  "1月",
  "2月",
  "3月",
  "4月",
  "5月",
  "6月",
  "7月",
  "8月",
  "9月",
  "10月",
  "11月",
  "12月",
];
export default {
  data() {
    return {
      value: "",
    };
  },
  methods: {
    // 1. 当月份时间选择器获取焦点的时候会弹出月份面板
    focusFn() {
      // 2. 要等到dom渲染完毕后,才能做dom内容替换,故使用$nextTick
      this.$nextTick(() => {
        // 3. 获取月份面板内的承载月份文字的a标签,建议大家审查dom看一下
        let monthArr = document.querySelectorAll(
          ".el-month-table tbody tr td a"
        );
        // 8. 后续再获取焦点摊开月份面板的时候,需要看看是否已经做了中文转数字替换
        if (numMonthArr.includes(monthArr[0].innerHTML)) {
          // 9. 要是替换过了就不操作了即可
          return;
        }
        // 4. 然后循环这个dom数组
        for (let i = 0; i < monthArr.length; i++) {
          let aDom = monthArr[i];
          // 5. 然后把a标签的中文内容更改为数字内容
          aDom.innerHTML = chineseToNum(aDom.innerHTML);
        }
      });
    },
  },
};
</script>