vue3基础组件开发detePicker日期选择组件示例

 更新时间:2023年03月01日 08:32:16   作者:Maya本尊  
这篇文章主要为大家介绍了vue3基础组件开发-detePicker(日期选择组件)示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

前言

使用了vue3有很长一段时间了,写了很多的基础组件在自己使用,整理一下(尽量使用最简单的方式实现),当做对自己知识的梳理。

技术栈

vue3 + tailwindcss + ts

页面开发

html结构

<template>
  <div>
      <-- 这里放input框 -->
      <div></div>
      <-- 点击input弹出日历 -->
      <div>
          <-- 头部 -->
          <div></div>
          <-- 星期 -->
          <div></div>
          <-- 日历主体 -->
          <div></div>
          <-- 按钮组 -->
          <div></div>
      </div>
  </div>
</template>

input框,

代码如下:

  <div class="block w-full h-[32px] relative border rounded-md">
      <input
        class="placeholder:text-[#B2B2B2] block w-full h-full rounded-md py-2 pl-2 pr-9 text-sm focus:outline-none focus:ring-0"
        disabled
        placeholder="选择时间"
        type="text"
        maxlength="32"
      />
      <div
        class="absolute inset-y-0 right-0 flex items-center pr-2 cursor-pointer"
      >
        <svg class="w-4 h-4 fill-[#C2C2C2]">
          <use xlink:href="#icon-riqi" rel="external nofollow"  />
        </svg>
      </div>
    </div>

头部,

代码如下

<div class="flex justify-center">
  <svg class="w-4 h-4 fill-[#C2C2C2] rotate-90 cursor-pointer">
    <use xlink:href="#icon-down" rel="external nofollow"  rel="external nofollow"  />
  </svg>
  <span class="text-xs mx-5">二月2023</span>
  <svg class="w-4 h-4 fill-[#C2C2C2] rotate-[270deg] cursor-pointer">
    <use xlink:href="#icon-down" rel="external nofollow"  rel="external nofollow"  />
  </svg>
</div>

星期,

代码如下:

<div
  class="grid grid-cols-7 auto-cols-[20px] auto-rows-[20px] text-xs mt-2 mx-[9px] justify-items-center gap-x-2.5"
>
  <span>一</span>
  <span>二</span>
  <span>三</span>
  <span>四</span>
  <span>五</span>
  <span>六</span>
  <span>日</span>
</div>

日历主体,

代码如下:

<div
  class="grid grid-cols-7 auto-cols-[20px] auto-rows-[20px] text-xs mt-2 mx-[9px] gap-y-2 gap-x-2.5"
>
  <span
    :class="[
      'cursor-pointer w-full h-full  flex justify-center items-center',
      v.color,
      {
        '!bg-[#60C2CC] rounded-full !text-white':
          actives.one === v.time || actives.two === v.time,
      },
      setBgColor(v.time),
    ]"
    v-for="(v, i) in days"
    :key="i"
    >{{ v.day }}</span
  >
</div>

这里主要是用了,v-bind动态属性,来显示不同状态下的日历格子的样式(比如选中某天)

按钮组,

代码如下:

<div class="flex justify-between items-center mt-2.5 mx-[9px]">
  <span class="text-xs text-[#9C9C9C]">跳到今天</span>
  <div
    class="w-[50px] h-5 bg-[#60C2CC] rounded-lg text-white leading-5 text-center text-xs"
  >
    确定
  </div>
</div>

整体样式如下:

逻辑开发

显示切换逻辑,主要是点击input,弹出日历

// 控制显示的变量
const isShow = ref(false)
// 点击按钮的时候显示
const openTimeSelect = () => {
  isShow.value = true
}
// 点击确定,或者点击日历主体外的任何窗体的时候关闭,关闭的时候清空选中
const closeTimeSelect = () => {
  isShow.value = false
  actives.one = ''
  actives.two = ''
}

定义变量,主要是定义日历用到的数据,和接口

// 本组件唯一定义的类型
interface DaysType {
  day: number
  color: string
  time: string
}
const date = new Date() // 时间
const year = ref(0) // 年
const month = ref(0) // 月
const days = ref<DaysType[]>([]) // 需要循环渲染的日历主体数据
// 选中某天的数据,可以选中两天
const actives = reactive({
  one: '',
  two: '',
})
// 计算属性,把当前点击选中的日期转换成时间戳
const oneTimeNum = computed(() => new Date(actives.one).getTime())
const twoTimeNum = computed(() => new Date(actives.two).getTime())

为什么说,使用ts写的代码,但是只定义了一个接口,在vue3 + ts的开发中,我推荐的是使用类型推导的方式去写代码,有时候,你会发现,你写的ts类型多此一举。当然,你是ts艺术体操选手,那另说······

获取日历主体渲染的数据,逻辑如下: 具体代码如下:

const updateTime = () => {
  days.value = []
  year.value = date.getFullYear() // 获取当前年
  month.value = date.getMonth() + 1 // 获取当前月份
  const curDays = new Date(year.value, month.value, 0).getDate() // 当前月的天数
  let curWeek = new Date(year.value, month.value - 1, 1).getDay() // 这个月第一天星期几
  curWeek <= 0 ? (curWeek = 7) : curWeek // 如果值是0的话,那么本月第一天是周日
  const preDays = new Date(year.value, month.value - 1, 0).getDate() // 上个月的天数
  const preLastDay = curWeek - 1 // 获取上一个月有多少天
  // 插入上一个月的日期
  for (let i = 0; i < preLastDay; i++) {
    days.value.unshift({
      day: preDays - i,
      color: 'text-[#CECECE]',
      time: `${year.value}-${month.value - 1}-${preDays - i}`,
    })
  }
  // 插入本月的日期
  for (let i = 1; i <= curDays; i++) {
    days.value.push({
      day: i,
      color: 'text-[#191919]',
      time: `${year.value}-${month.value}-${i}`,
    })
  }
  const lastPreDays = 42 - curDays - preLastDay
  // 插入下个月的日期
  for (let i = 1; i <= lastPreDays; i++) {
    days.value.push({
      day: i,
      color: 'text-[#CECECE]',
      time: `${year.value}-${month.value + 1}-${i}`,
    })
  }
}
  • 日历主体分为三个部分,1、前一个月的天数,2、当前月的天数,3、下一个月的天数
  • 通过date 内置对象,获取到:当前年,当前月,当前月有几天,当前月的第一天是星期几,上个月有多少天
  • 通过 当前月第一天是星期几 减去 1 得到,上个月一共有几天要显示
  • 获取上个月的天数 循环 上个月一共有几天,得到上个月具体的日期,比如说:
    • 上个月有2天要显示,上个月一共有31天,那么本月第一天往前两个格子是上月的。
    • 2次循环
    • 第一次,31 - 0 得到31
    • 第二次,31 - 1 得到30
    • 如下图所示:

  • 获取本月的天数 通过循环当前月的天数获取
  • 获取下月的天数 一共42个格子,那么42 减去当前月天数,减去上个月天数,就是下个月要显示多少天,同样循环获取

上一月和下一月

// 上一月
const prevMonth = () => {
  date.setMonth(date.getMonth() - 1)
  updateTime()
}
// 下一月
const nextMonth = () => {
  date.setMonth(date.getMonth() + 1)
  updateTime()
}
  • 主要是通过 dete 对象的 setMonth 方法重置月份,月份重置后,调用获日历主体方法就可获取到上一个月和下一个月的日历主体

选择两个日期选中,逻辑如下:

const selectTime = (item: DaysType) => {
  const timeNum = new Date(item.time).getTime()
  if (!actives.one || timeNum < oneTimeNum.value) {
    actives.one = item.time
  }
  if (!actives.two || timeNum > oneTimeNum.value) {
    actives.two = item.time
  }
}
  • 首先在html中绑定点击事件,点击获取的时候把当前选中的对象传递下来
  • 对象中有个字段是 2023-2-28 这样的格式,这个格式,可以通过 date 对象的 getTime 方法转换成时间戳
  • 如果第一次选中没有值,或者 当前选中的值小于 第一次选中的日期,那么存入第一次选中
  • 如果第二次选中没有纸,或者 当前选中的值大于 第一次选中的日期,那么存入第二次选中
  • 请注意:这里存入的时候,会自动通过计算属性把值转换为时间戳

给两个点之间添加背景色,逻辑如下:

const setBgColor = (time: string) => {
  const timeNum = new Date(time).getTime()
  if (
    oneTimeNum.value &&
    twoTimeNum.value &&
    oneTimeNum.value <= timeNum &&
    timeNum <= twoTimeNum.value
  ) {
    return 'bg-[#DFF3F5]'
  }
}
  • 还是通过转换时间戳的方式,去做对比
  • 处于两个选中日期中间的 格子 会返回个背景色
  • 然后通过动态class的方式插入颜色就可以了
  • 演示如下:

尾声

其实还有更多可深入研究的点,比如:内置对象 date 为啥能够通过准确获取到当前月的天数等,实现原理是啥,还有其它日期组件扩展,比如props传参,比如多类型(周日历等)选择等等。 但是最终考虑到这是vue3组件相关知识的梳理(传参没必要讲,官方已经写的很好了),以及其它周日历等类型在代码层面上来说,只需稍稍调整,思路还是这个思路,感觉没啥必要去啰嗦,所以点到为止吧。 

以上就是vue3基础组件开发-detePicker(日期选择组件)的详细内容,更多关于vue3基础组件detePicker的资料请关注脚本之家其它相关文章!

相关文章

  • cesium开发之如何在vue项目中使用cesium,使用离线地图资源

    cesium开发之如何在vue项目中使用cesium,使用离线地图资源

    这篇文章主要介绍了cesium开发之如何在vue项目中使用cesium,使用离线地图资源问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • vue 引入公共css文件的简单方法(推荐)

    vue 引入公共css文件的简单方法(推荐)

    下面小编就为大家分享一篇vue 引入公共css文件的简单方法(推荐),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-01-01
  • 一个Vue页面的内存泄露分析详解

    一个Vue页面的内存泄露分析详解

    这篇文章主要介绍了一个Vue页面的内存泄露分析详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-06-06
  • vue.js项目中实用的小技巧汇总

    vue.js项目中实用的小技巧汇总

    这篇文章主要给大家介绍了关于vue.js项目中实用的小技巧,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2017-11-11
  • vue中的数据格式化filters、formatter方式

    vue中的数据格式化filters、formatter方式

    这篇文章主要介绍了vue中的数据格式化filters、formatter方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-07-07
  • 利用Vue3+Element Plus封装公共表格组件(带源码)

    利用Vue3+Element Plus封装公共表格组件(带源码)

    最近公司项目中频繁会使用到table表格,而且前端技术这一块也用到了vue3来开发,所以基于element plus table做了一个二次封装的组件,这篇文章主要给大家介绍了关于利用Vue3+Element Plus封装公共表格组件的相关资料,需要的朋友可以参考下
    2023-11-11
  • 关于Vue中的watch监视属性

    关于Vue中的watch监视属性

    这篇文章主要介绍了关于Vue中的watch监视属性,Vue中的watch默认不监视对象内部值的改变,当被监视的属性变化时,回调函数自动调用,进行相关操作,需要的朋友可以参考下
    2023-04-04
  • 十分钟带你读懂Vue中的过滤器

    十分钟带你读懂Vue中的过滤器

    过滤器提供给我们的一种数据处理方式。过滤器功能不是必须要使用的,因为它所实现的功能也能用计算属性或者函数调用的方式来实现。这篇文章主要为大家介绍了Vue中过滤器的使用,需要的可以了解一下
    2023-03-03
  • vue实现直播间点赞飘心效果的示例代码

    vue实现直播间点赞飘心效果的示例代码

    这篇文章主要介绍了vue实现直播间点赞飘心效果的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • vue中提示$index is not defined错误的解决方式

    vue中提示$index is not defined错误的解决方式

    这篇文章主要介绍了vue中提示$index is not defined错误的解决方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09

最新评论