Our community front-end uses the Element component library, and our back-end management system uses iView. The component libraries are great, but the date and time pickers don’t have the “year, month, day” component selection. While the related components provided by the two libraries are also great, they are sometimes not very useful, and it is not clear why many component libraries have abandoned the date linkage option. So consider making one yourself.

Convert the timestamp to date format

// timestamp is the timestamp new Date(timestamp) // Obtain the timestamp block object, such as: Sun Sep 02 2018 00:00:00 GMT+0800 (Chinese standard time) /* Obtain the year: New Date(timestamp).getfullyear () getMonth: new Date(timestamp).getmonth () + 1 get day: new Date(timestamp).getdate () get day:  new Date(timestamp).getDay() */Copy the code

Converts the date format (YYYY-MM-DD) to a timestamp

// New Date()'2018-9-2').getTime()
 new Date('2018-9-2').valueOf()
 Date.parse(new Date('2018-9-2'))
Copy the code

Compatibility problems in Internet Explorer

Note: the above code cannot or will not get a standard time value under IE10 (or at least IE10), because 2018-9-2 is not a standard date format (2018-09-02 is standard), and at least the Chrome kernel is fault-tolerant for us (presumably firefox as well). Therefore, you must do strict date string integration, do not be lazy

Date online selector based on Vue componentization

The date selection component serves the following purposes:

(1) The value will be passed to the parent component regardless of whether the date is complete or default, because the parent component will do relevant processing according to the date value (such as limiting the submission operation, etc.);

(2) The specific days should be self-adaptive, that is, 31 days for the big month, 30 days for the small month, 28 days for the ordinary year in February and 29 days for the leap year;

(3) If the number of days is selected as 31 (or 30) first, then the number of months is selected. If the number of months currently selected does not contain the number of days already selected, the number of days is cleared.

(4) If the parent component has a timestamp passed in, the time should be displayed for the component to modify.

Implementation code (using the Vue + Element component library)

<template>
    <div class="date-pickers">
       <el-select 
       class="year select"
       v-model="currentDate.year"
        @change='judgeDay'
        placeholder="Year">
          <el-option
            v-for="item in years"
            :key="item"
            :label="item"
            :value="item">
          </el-option>
       </el-select>
       <el-select 
       class="month select"
       v-model="currentDate.month" 
       @change='judgeDay'
       placeholder="Month">
          <el-option
            v-for="item in months"
            :key="item"
            :label="String(item).length==1? String('0'+item):String(item)"
            :value="item">
          </el-option>
       </el-select>
       <el-select 
       class="day select"
       :class="{'error':hasError}"
       v-model="currentDate.day" 
       placeholder="Day">
          <el-option
            v-for="item in days"
            :key="item"
            :label="String(item).length==1? String('0'+item):String(item)"
            :value="item">
          </el-option>
       </el-select>
    </div>
</template>
<script>
export default {
  props: {
    sourceDate: {
      type: [String, Number]
    }
  },
  name: "date-pickers".data() {
    return {
      currentDate: {
        year: "",
        month: "",
        day: ""
      },
      maxYear: new Date().getFullYear(),
      minYear: 1910,
      years: [],
      months: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
      normalMaxDays: 31,
      days: [],
      hasError: false
    };
  },
  watch: {
    sourceDate() {
      if(this.sourceDate) { this.currentDate = this.timestampToTime(this.sourceDate); }},normalMaxDays() {
      this.getFullDays();
      if (this.currentDate.year && this.currentDate.day > this.normalMaxDays) {
        this.currentDate.day = "";
      }
    },
    currentDate: {
      handler(newValue, oldValue) {
        this.judgeDay();
        if (newValue.year && newValue.month && newValue.day) {
          this.hasError = false;
        } else {
          this.hasError = true;
        }
        this.emitDate();
      },
      deep: true}},created() {
    this.getFullYears();
    this.getFullDays();
  },
  methods: {
    emitDate() {
      lettimestamp; // The parent component is passed to the timestamp form by defaultif ( this.currentDate.year && this.currentDate.month && this.currentDate.day) {
         let month = this.currentDate.month < 10 ? ('0'+ this.currentDate.month):this.currentDate.month;
         let day = this.currentDate.day < 10 ? ('0'+ this.currentDate.day):this.currentDate.day;
         let dateStr = this.currentDate.year + "-" + month + "-" + day;
         timestamp = new Date(dateStr).getTime();
      } 
      else {
         timestamp = "";
      }
      this.$emit("dateSelected", timestamp);
    },
    timestampToTime(timestamp) {
      let dateObject = {};
      if (typeof timestamp == "number") {
        dateObject.year = new Date(timestamp).getFullYear();
        dateObject.month = new Date(timestamp).getMonth() + 1;
        dateObject.day = new Date(timestamp).getDate();
        returndateObject; }},getFullYears() {
      for (leti = this.minYear; i <= this.maxYear; i++) { this.years.push(i); }},getFullDays() {
      this.days = [];
      for (leti = 1; i <= this.normalMaxDays; i++) { this.days.push(i); }},judgeDay() {
      if([4, 6, 9, 11].indexOf(this.currentDate.month) ! == -1) { this.normalMaxDays = 30; // Month 30 daysif (this.currentDate.day && this.currentDate.day == 31) {
          this.currentDate.day = ""; }}else if (this.currentDate.month == 2) {
        if (this.currentDate.year) {
          if( (this.currentDate.year % 4 == 0 && this.currentDate.year % 100 ! = 0) || this.currentDate.year % 400 == 0 ) { this.normalMaxDays = 29; // Leap year February 29 days}else{ this.normalMaxDays = 28; // Leap year 28 days}}else{ this.normalMaxDays = 28; // Leap year 28 days}}else{ this.normalMaxDays = 31; // Big month 31 days}}}}; </script> <style lang="less">
.date-pickers {
  .select {
    margin-right: 10px;
    width: 80px;
    text-align: center;
  }
  .year {
    width: 100px;
  }
  .error {
    .el-input__inner {
      border: 1px solid #f1403c;
      border-radius: 4px;
    }
  }
}
</style>
Copy the code

Code parsing

The default normalMaxDays is 31 days, the minimum year is 1910, and the maximum year is the current year (since my business scenario is to fill in the birthday, you can change this yourself) and the year and day are initialized in the Created hook first.

Listen for currentDate (currentDate)

The core is to listen for every date change and correct normalMaxDays. This is a deep listen for currentDate and sends it to the parent component.

watch: { currentDate: { handler(newValue, oldValue) { this.judgeDay(); // Update the current number of days this.emitDate(); }, deep:true}}Copy the code

JudgeDay method:

judgeDay() {
  if([4, 6, 9, 11].indexOf(this.currentDate.month) ! == -1) { this.normalMaxDays = 30; // Month 30 daysif (this.currentDate.day && this.currentDate.day == 31) {
      this.currentDate.day = ""; }}else if (this.currentDate.month == 2) {
    if (this.currentDate.year) {
      if( (this.currentDate.year % 4 == 0 && this.currentDate.year % 100 ! = 0) || this.currentDate.year % 400 == 0 ) { this.normalMaxDays = 29; // Leap year February 29 days}else{ this.normalMaxDays = 28; // February 28 days}}else{ this.normalMaxDays = 28; // February 28 days}}else{ this.normalMaxDays = 31; // Month 31 days}}Copy the code

In the beginning I used includes to determine if the current month is a small month:

if([4, 6, 9, 11].includes(this.currentDate.month))
Copy the code

This includes is not supported in IE10, so use normal indexOf() instead.

EmitDate:

emitDate() {
  lettimestamp; // The parent component is passed to the timestamp form by defaultif ( this.currentDate.year && this.currentDate.month && this.currentDate.day) {
     let month = this.currentDate.month < 10 ? ('0'+ this.currentDate.month):this.currentDate.month;
     let day = this.currentDate.day < 10 ? ('0'+ this.currentDate.day):this.currentDate.day;
     let dateStr = this.currentDate.year + "-" + month + "-" + day;
     timestamp = new Date(dateStr).getTime();
  } 
  else {
     timestamp = "";
  }
  this.$emit("dateSelected", timestamp); // Send the result to the parent component},Copy the code

It’s important to note that standard date formatting is not done initially because Chrome is fault-tolerant, but not in IE10, so it’s best to do it.

NormalMaxDays After the change, you must obtain the days again and clear the selected days as required:

watch: {
    normalMaxDays() {
      this.getFullDays();
      if (this.currentDate.year && this.currentDate.day > this.normalMaxDays) {
        this.currentDate.day = ""; }}}Copy the code

The final result

Technology sucks!! Hope to exchange and learn with you! thank you