vue3基礎(chǔ)組件開發(fā)detePicker日期選擇組件示例
前言
使用了vue3有很長一段時間了,寫了很多的基礎(chǔ)組件在自己使用,整理一下(盡量使用最簡單的方式實(shí)現(xiàn)),當(dāng)做對自己知識的梳理。
技術(shù)棧
vue3 + tailwindcss + ts
頁面開發(fā)
html結(jié)構(gòu)
<template>
<div>
<-- 這里放input框 -->
<div></div>
<-- 點(diǎn)擊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動態(tài)屬性,來顯示不同狀態(tài)下的日歷格子的樣式(比如選中某天)
按鈕組,

代碼如下:
<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>
整體樣式如下:

邏輯開發(fā)
顯示切換邏輯,主要是點(diǎn)擊input,彈出日歷
// 控制顯示的變量
const isShow = ref(false)
// 點(diǎn)擊按鈕的時候顯示
const openTimeSelect = () => {
isShow.value = true
}
// 點(diǎn)擊確定,或者點(diǎn)擊日歷主體外的任何窗體的時候關(guān)閉,關(guān)閉的時候清空選中
const closeTimeSelect = () => {
isShow.value = false
actives.one = ''
actives.two = ''
}
定義變量,主要是定義日歷用到的數(shù)據(jù),和接口
// 本組件唯一定義的類型
interface DaysType {
day: number
color: string
time: string
}
const date = new Date() // 時間
const year = ref(0) // 年
const month = ref(0) // 月
const days = ref<DaysType[]>([]) // 需要循環(huán)渲染的日歷主體數(shù)據(jù)
// 選中某天的數(shù)據(jù),可以選中兩天
const actives = reactive({
one: '',
two: '',
})
// 計算屬性,把當(dāng)前點(diǎn)擊選中的日期轉(zhuǎn)換成時間戳
const oneTimeNum = computed(() => new Date(actives.one).getTime())
const twoTimeNum = computed(() => new Date(actives.two).getTime())
為什么說,使用ts寫的代碼,但是只定義了一個接口,在vue3 + ts的開發(fā)中,我推薦的是使用類型推導(dǎo)的方式去寫代碼,有時候,你會發(fā)現(xiàn),你寫的ts類型多此一舉。當(dāng)然,你是ts藝術(shù)體操選手,那另說······

獲取日歷主體渲染的數(shù)據(jù),邏輯如下: 具體代碼如下:
const updateTime = () => {
days.value = []
year.value = date.getFullYear() // 獲取當(dāng)前年
month.value = date.getMonth() + 1 // 獲取當(dāng)前月份
const curDays = new Date(year.value, month.value, 0).getDate() // 當(dāng)前月的天數(shù)
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() // 上個月的天數(shù)
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、前一個月的天數(shù),2、當(dāng)前月的天數(shù),3、下一個月的天數(shù)
- 通過date 內(nèi)置對象,獲取到:當(dāng)前年,當(dāng)前月,當(dāng)前月有幾天,當(dāng)前月的第一天是星期幾,上個月有多少天
- 通過 當(dāng)前月第一天是星期幾 減去 1 得到,上個月一共有幾天要顯示
- 獲取上個月的天數(shù) 循環(huán) 上個月一共有幾天,得到上個月具體的日期,比如說:
- 上個月有2天要顯示,上個月一共有31天,那么本月第一天往前兩個格子是上月的。
- 2次循環(huán)
- 第一次,31 - 0 得到31
- 第二次,31 - 1 得到30
- 如下圖所示:

- 獲取本月的天數(shù) 通過循環(huán)當(dāng)前月的天數(shù)獲取
- 獲取下月的天數(shù) 一共42個格子,那么42 減去當(dāng)前月天數(shù),減去上個月天數(shù),就是下個月要顯示多少天,同樣循環(huán)獲取
上一月和下一月
// 上一月
const prevMonth = () => {
date.setMonth(date.getMonth() - 1)
updateTime()
}
// 下一月
const nextMonth = () => {
date.setMonth(date.getMonth() + 1)
updateTime()
}
- 主要是通過 dete 對象的 setMonth 方法重置月份,月份重置后,調(diào)用獲日歷主體方法就可獲取到上一個月和下一個月的日歷主體
選擇兩個日期選中,邏輯如下:
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中綁定點(diǎn)擊事件,點(diǎn)擊獲取的時候把當(dāng)前選中的對象傳遞下來
- 對象中有個字段是 2023-2-28 這樣的格式,這個格式,可以通過 date 對象的 getTime 方法轉(zhuǎn)換成時間戳
- 如果第一次選中沒有值,或者 當(dāng)前選中的值小于 第一次選中的日期,那么存入第一次選中
- 如果第二次選中沒有紙,或者 當(dāng)前選中的值大于 第一次選中的日期,那么存入第二次選中
- 請注意:這里存入的時候,會自動通過計算屬性把值轉(zhuǎn)換為時間戳
給兩個點(diǎn)之間添加背景色,邏輯如下:
const setBgColor = (time: string) => {
const timeNum = new Date(time).getTime()
if (
oneTimeNum.value &&
twoTimeNum.value &&
oneTimeNum.value <= timeNum &&
timeNum <= twoTimeNum.value
) {
return 'bg-[#DFF3F5]'
}
}
- 還是通過轉(zhuǎn)換時間戳的方式,去做對比
- 處于兩個選中日期中間的 格子 會返回個背景色
- 然后通過動態(tài)class的方式插入顏色就可以了
- 演示如下:

尾聲
其實(shí)還有更多可深入研究的點(diǎn),比如:內(nèi)置對象 date 為啥能夠通過準(zhǔn)確獲取到當(dāng)前月的天數(shù)等,實(shí)現(xiàn)原理是啥,還有其它日期組件擴(kuò)展,比如props傳參,比如多類型(周日歷等)選擇等等。 但是最終考慮到這是vue3組件相關(guān)知識的梳理(傳參沒必要講,官方已經(jīng)寫的很好了),以及其它周日歷等類型在代碼層面上來說,只需稍稍調(diào)整,思路還是這個思路,感覺沒啥必要去啰嗦,所以點(diǎn)到為止吧。
以上就是vue3基礎(chǔ)組件開發(fā)-detePicker(日期選擇組件)的詳細(xì)內(nèi)容,更多關(guān)于vue3基礎(chǔ)組件detePicker的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
解決Vue項目打包后打開index.html頁面顯示空白以及圖片路徑錯誤的問題
這篇文章主要介紹了解決Vue項目打包后打開index.html頁面顯示空白以及圖片路徑錯誤的問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10
vue3.0在子組件中觸發(fā)的父組件函數(shù)方式
這篇文章主要介紹了vue3.0在子組件中觸發(fā)的父組件函數(shù)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-04-04
vue 中常用操作數(shù)組的方法(forEach()和reduce())
文章介紹了JavaScript中常用的操作數(shù)組方法,包括forEach()和reduce(),forEach()用于遍歷數(shù)組并對每個元素執(zhí)行操作,而reduce()則用于遍歷數(shù)組并進(jìn)行累加等迭代操作,感興趣的朋友一起看看吧2025-03-03
vue 2.8.2版本配置剛進(jìn)入時候的默認(rèn)頁面方法
今天小編就為大家分享一篇vue 2.8.2版本配置剛進(jìn)入時候的默認(rèn)頁面方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-09-09
ElementUI中el-form組件的rules參數(shù)舉例詳解
Form組件提供了表單驗(yàn)證的功能,只需要通過rules屬性傳入約定的驗(yàn)證規(guī)則,并將Form-Item的prop屬性設(shè)置為需校驗(yàn)的字段名即可,下面這篇文章主要給大家介紹了關(guān)于ElementUI中el-form組件的rules參數(shù)的相關(guān)資料,需要的朋友可以參考下2023-10-10

