基于el-date-picker的二次封装(vue2+elementui)

初衷:在工作的时候我们经常用到一些日期选择框,我发现尤其是用时间段选择的时候,elementui给我们的是一个数组,需要我们自己处理,把startDate和endDate提出来分开双向绑定的话可以减少很多操作,包括各种传值,封装后统一处理,后期维护起来就没有那么累。(ps:本文章只做了常用的date/daterange的处理)

  1. 首先看下封装后组件的用法

(1)这里是单个日期的时候,直接通过v-model绑定就可以了,跟elementui的原生组件没有任何区别

<date-picker

  type="date"
  v-model="value"
  ></date-picker>

(2)这是时间段的用法,vue2双向绑定多个值只能用这个写法,vue3就可以写多个v-model了

<date-picker

  type="daterange"
  :startDate.sync="params.startDate"
  :endDate.sync="params.endDate"
  ></date-picker>

这样用起来是不是感觉好多了,就不需要再单独处理时间段格式了,并且组件内部可以统一风格,话不多说,让我们看看组件怎么实现的吧!

  1. 首先这是html代码,以及一些常用的自定义属性,这些属性如不能满足可以自行根据elemenui的文档扩展
<template>
  <el-date-picker
    v-model="date"
    :type="type"
    :format="format"
    :value-format="valueFormat"
    :range-separator="rangeSeparator"
    :placeholder="placeholder"
    :start-placeholder="startPlaceholder"
    :end-placeholder="endPlaceholder"
  >
  </el-date-picker>
</template>
  }
export default {
  data() {
    return {
      date: null
    }
  },
  props: {
    /**
     * 显示类型 year/month/date/dates/months/years week/datetime/datetimerange/ daterange/monthrange
     * 暂时只对 date/daterange(很常用) 做了处理,其他的建议用element原生的组件,自行处理数据
     */
    type: {
      type: String,
      default: 'date'
    },
    value: {
      type: String,
      default: ''
    },
    startDate: {
      type: String,
      default: ''
    },
    endDate: {
      type: String,
      default: ''
    },
    // 文本格式
    format: {
      type: String,
      default: 'yyyy-MM-dd'
    },
    // 绑定值格式(这里的日期格式化参照elementui的时间格式,并不是dayjs的)
    valueFormat: {
      type: String,
      default: 'yyyy-MM-dd HH:mm:ss'
    },
    // 单个日期下的提示文案
    placeholder: {
      type: String,
      default: '选择日期'
    },
    // daterange 模式下选框1的提示文案
    startPlaceholder: {
      type: String,
      default: '开始日期'
    },
    // daterange 模式下选框2的提示文案
    endPlaceholder: {
      type: String,
      default: '结束日期'
    },
    // 选择范围时的分隔符
    rangeSeparator: {
      type: String,
      default: '至'
    }
  },

3.首先我们需要监听绑定的值:date,这里对null的情况单独做了处理,否则会报错,并且为null的时候,我没有区分type为date还是daterange的情况,单纯不想写太多if嵌套。这儿自定义了input事件是vue默认的model,有不清楚的小伙伴可以去了解一下vue2自定义v-model的相关知识。

methods: {
  // 根据日期选框不同type进行处理
    setDate(val) {
      if (Array.isArray(val)) {
        this.$emit('update:startDate', val[0])
        this.$emit('update:endDate', val[1])
      } else {
        this.$emit('input', val)
      }
    }
},
watch: {
   // 绑定值发生改变响应父组件
   date: {
      handler: function (newval, oldval) {
        if (newval) {
          this.setDate(newval)
        } else {
          this.$emit('input', '')
          this.$emit('update:startDate', '')
          this.$emit('update:endDate', '')
        }
      },
      deep: true
    }
}

4.接下来我们就要接收父组件传过来的默认值,对其处理,以便显示在选框上面

(1)这是type为daterange的情况

watch: {

    // 默认开始时间和结束时间
    startDate: {
      handler: function (val) {
        if (val) {
          this.$set(this.date, 0, val)
        }
      },
      immediate: true
    },
    endDate: {
      handler: function (val) {
        if (val) {
          this.$set(this.date, 1, val)
        }
      },
      immediate: true
    },
}

(2)这是type为date的情况,这种情况我直接在监听type的时候处理了。监听type对date进行默认赋值,因为type为date和daterange时候空状态的值类型不同。

watch: {

   type: {
      handler: function (val) {
        if (val == 'daterange') {
          this.date = ['', '']
        } else if (val == 'date') {
          this.date = this.value
        }
      },
      immediate: true
    },
}

5.整个实现过程就是这样了,其实非常简单,主要是针对时间段的时候提取他的开始和结束时间,这样父组件就不需要再对数据进行处理,直接就可以拿到想要的值。并且后期需要统一换风格或者相关配置项的时候也更加方便。最后附上完整代码。


<template>
  <el-date-picker
    v-model="date"
    :type="type"
    :format="format"
    :value-format="valueFormat"
    :range-separator="rangeSeparator"
    :placeholder="placeholder"
    :start-placeholder="startPlaceholder"
    :end-placeholder="endPlaceholder"
  >
  </el-date-picker>
</template>

<script>
export default {
  props: {
    /**
     * 显示类型 year/month/date/dates/months/years week/datetime/datetimerange/ daterange/monthrange
     * 暂时只对 date/daterange(很常用) 做了处理,其他的建议用element原生的组件,自行处理数据
     */
    type: {
      type: String,
      default: 'date'
    },
    value: {
      type: String,
      default: ''
    },
    startDate: {
      type: String,
      default: ''
    },
    endDate: {
      type: String,
      default: ''
    },
    // 文本格式
    format: {
      type: String,
      default: 'yyyy-MM-dd'
    },
    // 绑定值格式(这里的日期格式化参照elementui的时间格式,并不是dayjs的)
    valueFormat: {
      type: String,
      default: 'yyyy-MM-dd HH:mm:ss'
    },
    // 单个日期下的提示文案
    placeholder: {
      type: String,
      default: '选择日期'
    },
    // daterange 模式下选框1的提示文案
    startPlaceholder: {
      type: String,
      default: '开始日期'
    },
    // daterange 模式下选框2的提示文案
    endPlaceholder: {
      type: String,
      default: '结束日期'
    },
    // 选择范围时的分隔符
    rangeSeparator: {
      type: String,
      default: '至'
    }
  },
  data() {
    return {
      date: null
    }
  },
  methods: {
    // 根据日期选框不同type进行处理
    setDate(val) {
      if (Array.isArray(val)) {
        this.$emit('update:startDate', val[0])
        this.$emit('update:endDate', val[1])
      } else {
        this.$emit('input', val)
      }
    }
  },
  watch: {
    type: {
      handler: function (val) {
        if (val == 'daterange') {
          this.date = ['', '']
        } else if (val == 'date') {
          this.date = this.value
        }
      },
      immediate: true
    },
    // 默认开始时间和结束时间
    startDate: {
      handler: function (val) {
        if (val) {
          this.$set(this.date, 0, val)
        }
      },
      immediate: true
    },
    endDate: {
      handler: function (val) {
        if (val) {
          this.$set(this.date, 1, val)
        }
      },
      immediate: true
    },
    // 绑定值发生改变响应父组件
    date: {
      handler: function (newval, oldval) {
        if (newval) {
          this.setDate(newval)
        } else {
          this.$emit('input', '')
          this.$emit('update:startDate', '')
          this.$emit('update:endDate', '')
        }
      },
      deep: true
    }
  }
}
</script>

<style>
</style>

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MY11JkQl' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片