让 Vant 时间组件 van-datetime-picker 支持秒的一种巧妙的实现

6,037 阅读1分钟

Vant 的 DatetimePicker 组件是不支持选到秒的,如图

image.png

但业务又需要,于是自己基于 Vant DatetimePicker 组件实现了一个支持选年月日时分秒的日期时间组件 van-datetimesec-picker,先上效果图

image.png

实现原理其实很简单,就是在 vant 的 datetime-picker 组件右边塞一个 picker 组件,调整好样式和做好数据处理。

为了方便使用,搞了个 npm 包:www.npmjs.com/package/van…

这个包非常小巧,没有任何依赖,导出的是一个 vue 文件,所以需要项目依赖 vue sass vant

# 安装
npm i van-datetimesec-picker --save

# 引入
import VanDatetimesecPicker from 'van-datetimesec-picker'

# 注册
components: { VanDatetimesecPicker },

# 使用
<van-datetimesec-picker
  v-model="dateTime"
  :datetimePickerProps="{ 'visible-item-count': 3, title: '选择完整时间' }"
  :pickerProps="{ 'visible-item-count': 3 }"
/>

本质就是 van-datetime-picker 和 van-picker 拼起来的,支持为这两个组件单独传 props

Props

参数说明类型默认值
v-model (value)值(时间戳)number当前时间
datetimePickerPropsvan-datetime-picker 的 propsobject-
pickerPropsvan-picker 的 propsobject-

Events

事件说明回调参数
cancel点击取消时触发

示例

上面实现效果图的源码如下

<template>
  <div>
    <van-datetimesec-picker
      v-model="dateTime"
      :datetimePickerProps="{ 'visible-item-count': 3, title: '选择完整时间' }"
      :pickerProps="{ 'visible-item-count': 3 }"
    />
    <van-field
      label="日期时间"
      :value="new Date(dateTime).toLocaleString()"
      readonly
    />
    <van-field
      label="时间戳"
      :value="dateTime"
      @input="dateTime = +$event"
      type="number"
    />
  </div>
</template>

<script>
import VanDatetimesecPicker from 'van-datetimesec-picker'

export default {
  components: { VanDatetimesecPicker },
  data() {
    return {
      dateTime: Date.now()
    }
  }
}
<script>

效果如下:

image.png

源码

想要定制化开发,可以直接使用源码,也就70+行

<template>
  <div class="van-datetimesec-picker">
    <van-datetime-picker
      v-model="dateValue"
      type="datetime"
      v-bind="datetimePickerProps"
      @cancel="$emit('cancel')"
      @confirm="handleConfirm"
    />
    <van-picker
      :columns="Array(60).fill().map((_, i) => `0${i}`.slice(-2))"
      v-bind="pickerProps"
      :default-index="secondIdx"
      @change="handleChange"
    />
  </div>
</template>

<script>
export default {
  name: 'van-datetimesec-picker',
  props: {
    datetimePickerProps: Object,
    pickerProps: Object,
    value: Number
  },
  data() {
    return {
      secondIdx: 0,
      dateValue: null
    }
  },
  watch: {
    value: {
      handler() {
        this.dateValue = new Date(this.value)
        this.secondIdx = this.dateValue.getSeconds()
      },
      immediate: true
    }
  },
  methods: {
    handleConfirm(val) {
      val.setSeconds(this.secondIdx)
      this.$emit('input', val.getTime())
    },
    handleChange() {
      this.secondIdx = arguments[2]
    }
  }
}
</script>

<style lang="scss" scoped>
.van-datetimesec-picker {
  display: flex;
  .van-picker:first-of-type {
    flex: 5;
    ::v-deep {
      .van-picker__toolbar {
        width: 120%;
      }
      .van-picker__frame {
        width: 100%;
      }
    }
  }
  .van-picker:last-of-type {
    flex: 1;
    margin-top: 44px;
  }
}
</style>