基于elementui时间选择组件的二次封装

薛兴德
2023-12-01

组件部分

<template>
  <div class="my-date">
    <el-date-picker
      v-model="selectDateValue"
      :value-format="valueFormat"
      :type="type"
      :align="align"
      unlink-panels
      :popper-class="clearable ? '' : 'datePickerStyNoClear'"
      :range-separator="rangeSeparator"
      :start-placeholder="startPlaceholder"
      :end-placeholder="endPlaceholder"
      :picker-options="pickerOptions"
      :size="size"
      :default-time="defaultTime"
      :clearable="clearable"
      @change="handleChangeDate"
      @blur="blur"
    />
  </div>
</template>

<script>
import { shortcutsOptions, disabledDate } from './index.js';
import moment from 'moment';
import { deepClone } from '../../utils/index.js';
export default {
  model: {
    prop: 'value',
    event: 'changeDate',
  },
  props: {
    
    // 接收父组件v-mode传入的value值
    value: { type: Array, required: true },
    // 时间组件的类型
    type: {
      type: String,
      default: 'datetimerange',
    },
    // 组件的大小,默认小号的
    size: {
      type: String,
      default: 'small',
    },
    startPlaceholder: {
      type: String,
      default: '开始日期',
    },
    endPlaceholder: {
      type: String,
      default: '结束日期',
    },
    rangeSeparator: {
      type: String,
      default: '至',
    },
    
    // 日期格式  默认 yyyy-MM-dd HH:mm:ss
    // 想要 yyyy-MM-dd 形式的,在父组件传入 yyyy-MM-dd
    valueFormat: {
      type: String,
      required: false,
      default: 'yyyy-MM-dd HH:mm:ss',
    },
    // 日期选择界面的 对齐方式 默认 居中(center)
    align: {
      type: String,
      required: false,
      default: 'center',
    },
    // 是否展示快捷选项
    showShortcuts: {
      type: Boolean,
      default: true,
    },
    // 默认选择时间
    defaultSelectDays: {
      type: Number,
      default: 0,
    },
    momentSubtractParams:{
      type:String,
      default:'days'
    },
    // 最大时间间隔
    maxDateInterval: {
      type: Number,
      default: 30,
    },
    // 是否限制可选择时间,需要选择时间大于当前时间时候设置为 true
    isLimitTimeSelect:{
      type: Boolean,
      default: false,
    },
    formData:{
      type:Object,
      default:() => ({})
    },
    showClear: {
      type: Boolean,
      default: true,
    },
    // 需要排除得keys
    excludeKeys:{
      type:Array,
      default:() => []
    }
  },
  data() {
    let _this = this;
    return {
      defaultTime:['00:00:00', '23:59:59'],
      clearable:true,
      selfFormData:{},
      selectDateValue: [], // 选择日期存放的值
      pickerMinDate: null,
      pickerOptions: {
        disabledDate: (time) => disabledDate(time, _this),
        // 配置快捷日期选择
        shortcuts: shortcutsOptions(_this),
        onPick: (val) => {
          if (val.minDate && this.pickerMinDate) {
            this.pickerMinDate = null;
          } else if (val.minDate) {
            this.pickerMinDate = val.minDate.getTime();
          }
        },
      },
    };
  },
  watch: {
    formData:{
      deep:true,
      handler(val) {
        // 判断两个对象是否相同
        // const isChange = isObjectValueEqual(this.delectKeys(val), this.delectKeys(this.selfFormData));
        const changeFn = (obj) => {
          return Object.values(obj).every(item => {
            if (typeof item === 'object' && item !== null && !(item instanceof Date)) {
              if (Array.isArray(item)) {
                return !item.length;
              }
              return changeFn(item);
            } 
            return !item && (item !== 0);
          
          });
        };
        const isChange = changeFn(this.delectKeys(val));

        if (isChange) {
          this.setDefaultDate();
          this.clearable = false;
        } else {
          this.clearable = true;
        }
      }
    },
    value: {
      immediate: true,
      handler(val) {
        this.selectDateValue = val;
      },
    },
  },
  created() {
    this.clearable = this.showClear;
    // 如果没有赋值,不执行该操作
    if (Object.keys(this.formData).length > 0) {
      this.selfFormData = deepClone(this.formData);
      this.clearable = false;
    }
    // 组件赋默认值
    if (this.defaultSelectDays > 0) {
      this.setDefaultDate();
    } 
  },
  methods: {
    // 选择日期触发的事件
    handleChangeDate(val) {
      this.$emit('changeDate', val || []);
    },
    setDefaultDate() {
      const correctDefaultSelectDays = this.valueFormat === 'yyyy-MM-dd HH:mm:ss' ? (this.defaultSelectDays - 1) : this.defaultSelectDays;
      // 如果要时分秒
      if (this.type === 'daterange' && this.valueFormat !== 'yyyy-MM-dd HH:mm:ss') {
        const date = [moment().subtract(correctDefaultSelectDays, 'days').format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')];
        this.handleChangeDate(date);
        return; 
      }
      const date = [moment().subtract(correctDefaultSelectDays, 'days').format('YYYY-MM-DD 00:00:00'), moment().format('YYYY-MM-DD 23:59:59')];
      this.handleChangeDate(date);
    },
    delectKeys(obj) {
      const newObj = deepClone(obj);
      this.excludeKeys.forEach(item => {
        delete newObj[item];
      });
      return newObj;
    },
    blur() {
      this.pickerMinDate = null;
    }
  },
 
};
</script>
<style scoped lang='scss'>
::v-deep.el-date-editor--daterange.el-input,
.el-date-editor--daterange.el-input__inner,
.el-date-editor--timerange.el-input,
.el-date-editor--timerange.el-input__inner {
  width: 400px;
}
.datePickerStyNoClear .el-picker-panel__footer .el-button--text span {
  display: none !important;
}

</style>

js部分

import moment from 'moment';
export const getDefaultTime = () => {
  const startFormat = moment(new Date()).format('YYYY-MM-DD 00:00:00');
  const start = new Date(startFormat);
  const endFormat = moment(new Date()).format('YYYY-MM-DD 23:59:59');
  const end = new Date(endFormat);
  return {
    start,
    end,
  };
};
// 快捷选项 7天
const selectOption7Day = (_this) => {
  return [
    {
      text: '今天',
      onClick(picker) {
        const { start, end } = getDefaultTime();
        picker.$emit('pick', [start, end]);
      },
    },
    {
      text: '昨天',
      onClick(picker) {
        const { start, end } = getDefaultTime();
        end.setTime(end.getTime() - 3600 * 1000 * 24);
        start.setTime(start.getTime() - 3600 * 1000 * 24);
        picker.$emit('pick', [start, end]);
      },
    },
    {
      text: '过去7天',
      onClick:(picker) => {
        const { start, end } = getDefaultTime();
        const minusDay = _this.valueFormat === 'yyyy-MM-dd HH:mm:ss' ? 6 : 7;
        start.setTime(start.getTime() - 3600 * 1000 * 24 * minusDay);
        picker.$emit('pick', [start, end]);
      },
    }
  ];
};
// 快捷选项 30天
const selectOption30Day = (_this) => {
  return [
    ...selectOption7Day(_this),
    {
      text: '过去30天',
      onClick(picker) {
        const { start, end } = getDefaultTime();
        const minusDay = _this.valueFormat === 'yyyy-MM-dd HH:mm:ss' ? 29 : 30;
        start.setTime(start.getTime() - 3600 * 1000 * 24 * minusDay);
        picker.$emit('pick', [start, end]);
      },
    }
  ];
};
// 快捷选项 60天
const selectOption60Day = (_this) => {
  return [
    ...selectOption30Day(_this),
    {
      text: '过去60天',
      onClick(picker) {
        const { start, end } = getDefaultTime();
        const minusDay = _this.valueFormat === 'yyyy-MM-dd HH:mm:ss' ? 59 : 60;
        start.setTime(start.getTime() - 3600 * 1000 * 24 * minusDay);
        picker.$emit('pick', [start, end]);
      },
    },
  ];
};
// 快捷选项 90天
const selectOption90Day = (_this) => {
  return [
    ...selectOption60Day(_this),
    {
      text: '过去90天',
      onClick(picker) {
        const { start, end } = getDefaultTime();
        const minusDay = _this.valueFormat === 'yyyy-MM-dd HH:mm:ss' ? 89 : 90;
        start.setTime(start.getTime() - 3600 * 1000 * 24 * minusDay);
        picker.$emit('pick', [start, end]);
      },
    },
  ];
};



export const shortcutsOptions = (_this) => {
  if (_this.showShortcuts) {
    if ( _this.maxDateInterval < 7) {
      return null;
    } else if (_this.maxDateInterval >= 7 && _this.maxDateInterval < 30) {
      return selectOption7Day(_this);
    } else if (_this.maxDateInterval >= 30 && _this.maxDateInterval < 60) {
      return selectOption30Day(_this);
    } else if (_this.maxDateInterval >= 60 && _this.maxDateInterval < 90) {
      return selectOption30Day(_this);
    }
    return selectOption90Day(_this);
  }
  return null;
};


export const disabledDate = (time, _this) => {
  const maxDateIntervalTmime = (_this.maxDateInterval) * 24 * 3600 * 1000;
  if (_this.isLimitTimeSelect) {
    // 当不限制时间选择的时候,需要设定最大时间跨度
    if (_this.pickerMinDate) {
      return (
        time.getTime() >= (_this.pickerMinDate + maxDateIntervalTmime) ||
              time.getTime() <= _this.pickerMinDate - maxDateIntervalTmime
      );
    }
    return false;
  }

  if (_this.pickerMinDate) {
    return (
      time.getTime() >= (((_this.pickerMinDate + maxDateIntervalTmime) > new Date(moment(new Date()).format('YYYY,MM,DD 23:59:59'))) ? new Date(moment(new Date()).format('YYYY,MM,DD 23:59:59')) : (_this.pickerMinDate + maxDateIntervalTmime)) ||
              time.getTime() <= (((_this.pickerMinDate - maxDateIntervalTmime) < new Date(2018, 0, 18)) ? new Date(2018, 0, 18) : (_this.pickerMinDate - maxDateIntervalTmime))
    );
  }
        
  return (
    time.getTime() >
              new Date(moment(new Date()).format('YYYY,MM,DD 23:59:59')) ||
            time.getTime() < new Date(2018, 0, 18)
  );
};

使用

 <zz-time-picker v-model="appearDate" size="" :defaultSelectDays="30" />

1.父组件再页面首次加载时候,要获得appearDate的值,需要再mounted中使用(组件的加载顺序问题)
2.如果时间组件必须有值,设置showClear为false
3.如果筛选条件为空时候,时间必填,不为空时候,时间可填可不填,传入搜索条件的数据formData和需要排除的keys数组excludeKeys。组件会自动判断是否需要重新填充时间。

 类似资料: