vue3+ts 年月日时分秒时间组件改进

之前写了一个时间组件,然后稍有不足,现在改进一下,具体的改进点就是,原先的时候,我选择某年某月的话,发现天,每次都是31一天。然后用选了个11月31号,接口后端拿到这个日期,不出所料的报错了,因为去年11月是没有31号的,所以今天改进一下,改进的点就是,当van-picker时间改变的时候,就检测处于哪年,哪月,然后对于相应的年月,展示正确的天数,将这个天数的数组,展示在相对应的一列即可

下面我就是完整的组件代码:
 

<!--
 * @Description: 年月日时分秒 时间选择组件 
 * @FilePath: \shared\common\src\components\DateTimePicker
-->
<template>
  <!-- 参数说明
  /**
  *  |-Params[cellTitle] {String} 单元格名称 默认时间 (必传)
  *  |-Params[values] {String} 传入的时间值 格式为YYYY-MM-DD HH:mm:ss (必传)
  *  |-Params[disabled] {Boolean} 是否可被选中
  *  示例:<DateTimePicker :cellTitle="'创建时间'" :values="''" @dateConfirm="" :disabled="false"/>
  */
  -->
  <div :class="['date-box', { edit: !disabled }]">
    <van-cell
      :title="cellTitle"
      :is-link="!disabled"
      :value="values"
      @click="showPopup"
    />
  </div>

  <van-popup
    v-model:show="data.isPicker"
    position="bottom"
    round
    @close="closePop"
  >
    <van-picker
      ref="picker"
      v-model="data.selectedValues"
      title="请选择时间"
      :columns="data.columns"
      @change="onChange"
      @cancel="cancelOn"
      @confirm="onConfirm"
    >
      <template #columns-top>
        <div class="title" style="height: 3rem">
          <span>年</span>
          <span>月</span>
          <span>日</span>
          <span>时</span>
          <span>分</span>
          <span>秒</span>
        </div>
      </template>
    </van-picker>
  </van-popup>
</template>
<script setup lang="ts">
import {
  reactive,
  watch,
  getCurrentInstance,
  defineProps,
  defineEmits,
  ref,
  Ref
} from "vue";
import { format } from "date-fns";

const values: Ref<string> = ref(""); //时间值 YYYY-MM-DD HH:mm:ss

const emits = defineEmits(["dateConfirm"]);

const customFieldName = {
  text: "value",
  value: "values",
  children: ""
};
const data = reactive({
  isPicker: false, //是否显示弹出层
  columns: [], //所有时间列
  selectedValues: [] //控件选择的时间值
});

const props = defineProps({
  // 传入的值
  values: {
    type: String
  },
  // 单元格名称
  cellTitle: {
    type: String,
    required: false
  },
  // 是否可以选中
  disabled: {
    type: Boolean,
    required: false,
    default: false
  }
});

watch(
  () => props.values,
  val => {
    if (!val) {
      values.value = format(new Date(), "yyyy-MM-dd HH:mm:ss");
    } else {
      values.value = props.values;
    }
    data.columns = [];
    getcolumns();
  },
  {
    immediate: true
  }
);

/**
 * @description: 月份改变,获取天数
 */
function onChange(values) {
  const year = parseInt(values.selectedValues[0], 10);
  const month = parseInt(values.selectedValues[1], 10);
  // 获取当月天数
  const days = getCountDays(year, month);
  const daysArray = Array.from({ length: days }, (_, index) => {
    const day = index + 1;
    const columnDay = day.toString().padStart(2, "0");
    return { text: columnDay, value: columnDay };
  });

  data.columns[2] = daysArray;
}

function showPopup() {
  if (!props.disabled) {
    data.isPicker = true;
  }
}

/**
 * @description: 获取时间列
 */
function getcolumns() {
  const strtime = values.value; // 传入的时间
  const date = new Date(strtime.replace(/-/g, "/"));
  let dateVaules = date;

  if (!props.values) {
    dateVaules = new Date(); //当前的时间
  }

  const Y = dateVaules.getFullYear();
  const M = dateVaules.getMonth() + 1; // 月份是从0开始,所以+1
  const D = dateVaules.getDate();
  const h = dateVaules.getHours();
  const m = dateVaules.getMinutes();
  const s = dateVaules.getSeconds();

  // 补0
  const formatNumber = (num: number) => num.toString().padStart(2, "0");
  const _M = formatNumber(M);
  const _D = formatNumber(D);
  const _h = formatNumber(h);
  const _m = formatNumber(m);
  const _s = formatNumber(s);

  // 更新
  data.selectedValues = [Y, _M, _D, _h, _m, _s];

  // 年
  const years = Array.from({ length: 20 }, (_, i) => ({
    text: (Y - 10 + i).toString(),
    value: Y - 10 + i
  }));
  years.defaultIndex = years.findIndex(year => year.value === Y);
  data.columns.push(years);

  // 月
  const months = Array.from({ length: 12 }, (_, i) => ({
    text: formatNumber(i + 1),
    value: formatNumber(i + 1)
  }));
  data.columns.push(months);

  // 日期列表 根据当年与当月计算天数
  const days = getCountDays(Y, M);
  const daysOfMonth = Array.from({ length: days }, (_, i) => ({
    text: formatNumber(i + 1),
    value: formatNumber(i + 1)
  }));
  data.columns.push(daysOfMonth);

  // 时 分 秒
  const hours = Array.from({ length: 24 }, (_, i) => ({
    text: formatNumber(i),
    value: formatNumber(i)
  }));
  data.columns.push(hours);

  const minutes = Array.from({ length: 60 }, (_, i) => ({
    text: formatNumber(i),
    value: formatNumber(i)
  }));
  data.columns.push(minutes);

  const seconds = Array.from({ length: 60 }, (_, i) => ({
    text: formatNumber(i),
    value: formatNumber(i)
  }));
  data.columns.push(seconds);
}

/**
 * @description: 辅助函数 格式化数字,始终保持两位数
 * @param: num
 */
function formatNumber(num: number): string {
  return num.toString().padStart(2, "0");
}

/**
 * @description: 获取某年某月多少天
 * @param: year month
 */
function getCountDays(year, month) {
  let day = new Date(year, month, 0);
  return day.getDate();
}

/**
 * @description: 关闭底部弹窗
 * @param:
 */
function closePop() {
  data.isPicker = false;
}

/**
 * @description: 时间选择器关闭 值不改变并关闭弹框
 * @param: selectedValues 选中的值
 */
function cancelOn({ selectedValues }) {
  data.isPicker = false;
}

/**
 * @description: 时间选择器确认
 * @param: selectedValues 选中的时间值(Array)
 */
function onConfirm({ selectedValues }) {
  let endval =
    selectedValues[0] +
    "-" +
    selectedValues[1] +
    "-" +
    selectedValues[2] +
    " " +
    selectedValues[3] +
    ":" +
    selectedValues[4] +
    ":" +
    selectedValues[5];
  values.value = endval;
  data.isPicker = false;
  emits("dateConfirm", endval);
}
</script>

<style scoped lang="less">
.date-box {
  flex: 1;

  :deep(.van-cell) {
    padding: 0;

    .van-cell__value {
      color: #333;
    }
  }
}

.edit {
  :deep(.van-cell) {
    .van-cell__value {
      color: #3f72e4;
    }

    .van-icon {
      color: #3f72e4;
    }
  }
}

.title {
  min-height: 4rem;
  padding: 2rem 0;
  display: flex;
  justify-content: space-around;
  align-items: center;
  color: #323233;
  font-weight: 800;
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值