因为element-ui中的el-date-picker只有月份、日期范围选择,没有年份范围选择,而我们的项目需要选择年份范围,于是我想着试一试借助el-date-picker封装一个年份范围选择器。

效果展示

在这里插入图片描述
前言:前端从后端获取可以选择的年份范围

  1. 点击下方的快捷选项,最近一年,最近三年和最近五年,年份选择框会变成相应的年份(结束年份为可以选择的最大年份)
  2. 点击年份选择框也可以选择年份
  3. 当年份不合要求(如起始年份大于结束年份,年份超出范围),再点击确定的时候会有错误提示。

实现思路

年份范围选择

利用两个el-date-picker组件作为选择器,将type设置为‘year’
两个el-date-picker间用‘至’相隔
在最右边加上确定按钮

      <el-date-picker
        v-model="start"
        type="year"
        size="small"
        style="width: 100px"
        placeholder="开始年份"
      >
      </el-date-picker>
      <span style="margin-left: 5px; margin-right: 5px"></span>
      <el-date-picker
        v-model="end"
        type="year"
        size="small"
        style="width: 100px; margin-right: 5px"
        placeholder="结束年份"
      >
      </el-date-picker>
      <el-button size="small" type="primary" @click="handleClick"
        >确定</el-button
      >

年份范围快捷选项

用3个size为small的el-button作为快捷选项,绑定click事件

      <div style="text-align: left">
        <el-button
          type="text"
          size="small"
          style="display: inline"
          @click="handleShortCut(1)"
          >最近一年</el-button
        >
        <el-button
          type="text"
          size="small"
          style="display: inline"
          @click="handleShortCut(3)"
          >最近三年</el-button
        >
        <el-button
          type="text"
          size="small"
          style="display: inline"
          @click="handleShortCut(5)"
          >最近五年</el-button
        >
      </div>

click事件

    handleShortCut(val) {
      //date类型的数据,单纯的赋值实际上是浅拷贝,指向同一个地址,所以当一个变量变化,这个地址也会跟着变,所以要用到深拷贝
      Date.prototype.clone = function () {
        return new Date(this.valueOf());
      }

      //最近x年的结束年份
      this.end = this.maxYear.clone()
      //最近x年的开始年份
      let start = this.maxYear.clone()
      start.setFullYear(start.getFullYear() - val + 1)
      this.start = start.clone()
    },

点击确定按钮时将起始年份和结束年份导出

确定按钮绑定事件

<el-button size="small" type="primary" @click="handleClick">确定</el-button>

在导出前判断年份范围是否合法,并给出提示
如果年份范围合法,则父组件可以绑定get-year-range事件获取起始年份和结束年份

handleClick() {
      let start = this.start.getFullYear()
      let end = this.end.getFullYear()
      if (start < this.years[0] || end > this.years[this.years.length - 1]) {
        this.$message({
          type: 'error',
          message: '年份超出范围,请重新选择,范围为' + this.years[0] + '~' + this.years[this.years.length - 1]
        })
      } else if (start > end) {
        this.$message({
          type: 'error',
          message: '起始年份不能大于结束年份,请重新选择'   
        })
      } else {
        this.$emit('get-year-range', start, end)
      }
    },

实现难点

在给Date赋值和修改时,仅仅用let date=Date,这种对象赋值是传递的引用,是浅拷贝的方式,每次更改变量值,都会修改原始的Date

这边需要用深拷贝的方式拷贝Date对象

//date类型的数据,单纯的赋值实际上是浅拷贝,指向同一个地址,所以当一个变量变化,这个地址也会跟着变,所以要用到深拷贝
      Date.prototype.clone = function () {
        return new Date(this.valueOf());
      }

      //最近x年的end
      this.end = this.maxYear.clone()

如何使用

在script中导入组件
在这里插入图片描述
在components中声明组件
在这里插入图片描述
在template中使用
在这里插入图片描述
绑定get-year-range事件(两个参数,start,end)
在这里插入图片描述

相关代码

<template>
  <div>
    <div class="year-picker-box">
      <el-date-picker
        v-model="start"
        type="year"
        size="small"
        style="width: 100px"
        placeholder="开始年份"
      >
      </el-date-picker>
      <span style="margin-left: 5px; margin-right: 5px"></span>
      <el-date-picker
        v-model="end"
        type="year"
        size="small"
        style="width: 100px; margin-right: 5px"
        placeholder="结束年份"
      >
      </el-date-picker>
      <el-button size="small" type="primary" @click="handleClick"
        >确定</el-button
      >
      <br />
      <div style="text-align: left">
        <el-button
          type="text"
          size="small"
          style="display: inline"
          @click="handleShortCut(1)"
          >最近一年</el-button
        >
        <el-button
          type="text"
          size="small"
          style="display: inline"
          @click="handleShortCut(3)"
          >最近三年</el-button
        >
        <el-button
          type="text"
          size="small"
          style="display: inline"
          @click="handleShortCut(5)"
          >最近五年</el-button
        >
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'YearRangePicker',
  components: {
  },
  data() {
    return {
      years: [],
      start: null,
      end: null,
      minYear: null,//年份最小值
      maxYear: null,//年份最大值
    }
  },
  created() {
    this.getYears();
  },
  methods: {
    getYears() {
      this.axios({
        url: 'grad/yearList',
        methods: 'get'
      }).then(res => {
        this.years = res.data.data

        this.years = this.years.sort(function (a, b) {
          return a - b;
        })

        //最小年份,最大年份
        this.minYear = new Date('' + this.years[0] + '-1-1')
        this.maxYear = new Date('' + this.years[this.years.length - 1] + '-1-1')

        //默认为最近一年
        this.end = this.maxYear
        this.start = this.maxYear

      })
    },
    isEarlyThan(dateA, dateB) {
      // dateA 比 dateB 早则为 true(严格小于)
      const yearA = dateA.getFullYear();
      const yearB = dateB.getFullYear();

      if (yearA < yearB) {
        return true;
      } else {
        return false;
      }
    },
    handleShortCut(val) {
      //date类型的数据,单纯的赋值实际上是浅拷贝,指向同一个地址,所以当一个变量变化,这个地址也会跟着变,所以要用到深拷贝
      Date.prototype.clone = function () {
        return new Date(this.valueOf());
      }

      //最近x年的end
      this.end = this.maxYear.clone()
      //最近x年的start
      let start = this.maxYear.clone()
      start.setFullYear(start.getFullYear() - val + 1)
      this.start = start.clone()
    },
    handleClick() {
      let start = this.start.getFullYear()
      let end = this.end.getFullYear()
      if (start < this.years[0] || end > this.years[this.years.length - 1]) {
        this.$message({
          type: 'error',
          message: '年份超出范围,请重新选择,范围为' + this.years[0] + '~' + this.years[this.years.length - 1]
        })
      } else if (start > end) {
        this.$message({
          type: 'error',
          message: '起始年份不能大于结束年份,请重新选择'   
        })
      } else {
        this.$emit('get-year-range', start, end)
      }
    },
    disabledDate(time) {
      //查阅过官方文档后,发现需要返回boolean值
      return this.isEarlyThan(time, this.minYear) || this.isEarlyThan(this.maxYear, time);
    }
  }
}
</script>

<style scoped>
.year-picker-box {
  padding: 10px;
  width: 290px;
}
</style>
Logo

前往低代码交流专区

更多推荐