vue3基礎(chǔ)組件開(kāi)發(fā)detePicker日期選擇組件示例
前言
使用了vue3有很長(zhǎng)一段時(shí)間了,寫(xiě)了很多的基礎(chǔ)組件在自己使用,整理一下(盡量使用最簡(jiǎn)單的方式實(shí)現(xiàn)),當(dāng)做對(duì)自己知識(shí)的梳理。
技術(shù)棧
vue3 + tailwindcss + ts
頁(yè)面開(kāi)發(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="選擇時(shí)間" 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動(dòng)態(tài)屬性,來(lá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>
整體樣式如下:
邏輯開(kāi)發(fā)
顯示切換邏輯,主要是點(diǎn)擊input,彈出日歷
// 控制顯示的變量 const isShow = ref(false) // 點(diǎn)擊按鈕的時(shí)候顯示 const openTimeSelect = () => { isShow.value = true } // 點(diǎn)擊確定,或者點(diǎn)擊日歷主體外的任何窗體的時(shí)候關(guān)閉,關(guān)閉的時(shí)候清空選中 const closeTimeSelect = () => { isShow.value = false actives.one = '' actives.two = '' }
定義變量,主要是定義日歷用到的數(shù)據(jù),和接口
// 本組件唯一定義的類型 interface DaysType { day: number color: string time: string } const date = new Date() // 時(shí)間 const year = ref(0) // 年 const month = ref(0) // 月 const days = ref<DaysType[]>([]) // 需要循環(huán)渲染的日歷主體數(shù)據(jù) // 選中某天的數(shù)據(jù),可以選中兩天 const actives = reactive({ one: '', two: '', }) // 計(jì)算屬性,把當(dāng)前點(diǎn)擊選中的日期轉(zhuǎn)換成時(shí)間戳 const oneTimeNum = computed(() => new Date(actives.one).getTime()) const twoTimeNum = computed(() => new Date(actives.two).getTime())
為什么說(shuō),使用ts寫(xiě)的代碼,但是只定義了一個(gè)接口,在vue3 + ts的開(kāi)發(fā)中,我推薦的是使用類型推導(dǎo)的方式去寫(xiě)代碼,有時(shí)候,你會(huì)發(fā)現(xiàn),你寫(xiě)的ts類型多此一舉。當(dāng)然,你是ts藝術(shù)體操選手,那另說(shuō)······
獲取日歷主體渲染的數(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() // 這個(gè)月第一天星期幾 curWeek <= 0 ? (curWeek = 7) : curWeek // 如果值是0的話,那么本月第一天是周日 const preDays = new Date(year.value, month.value - 1, 0).getDate() // 上個(gè)月的天數(shù) const preLastDay = curWeek - 1 // 獲取上一個(gè)月有多少天 // 插入上一個(gè)月的日期 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 // 插入下個(gè)月的日期 for (let i = 1; i <= lastPreDays; i++) { days.value.push({ day: i, color: 'text-[#CECECE]', time: `${year.value}-${month.value + 1}-${i}`, }) } }
- 日歷主體分為三個(gè)部分,1、前一個(gè)月的天數(shù),2、當(dāng)前月的天數(shù),3、下一個(gè)月的天數(shù)
- 通過(guò)date 內(nèi)置對(duì)象,獲取到:當(dāng)前年,當(dāng)前月,當(dāng)前月有幾天,當(dāng)前月的第一天是星期幾,上個(gè)月有多少天
- 通過(guò) 當(dāng)前月第一天是星期幾 減去 1 得到,上個(gè)月一共有幾天要顯示
- 獲取上個(gè)月的天數(shù) 循環(huán) 上個(gè)月一共有幾天,得到上個(gè)月具體的日期,比如說(shuō):
- 上個(gè)月有2天要顯示,上個(gè)月一共有31天,那么本月第一天往前兩個(gè)格子是上月的。
- 2次循環(huán)
- 第一次,31 - 0 得到31
- 第二次,31 - 1 得到30
- 如下圖所示:
- 獲取本月的天數(shù) 通過(guò)循環(huán)當(dāng)前月的天數(shù)獲取
- 獲取下月的天數(shù) 一共42個(gè)格子,那么42 減去當(dāng)前月天數(shù),減去上個(gè)月天數(shù),就是下個(gè)月要顯示多少天,同樣循環(huán)獲取
上一月和下一月
// 上一月 const prevMonth = () => { date.setMonth(date.getMonth() - 1) updateTime() } // 下一月 const nextMonth = () => { date.setMonth(date.getMonth() + 1) updateTime() }
- 主要是通過(guò) dete 對(duì)象的 setMonth 方法重置月份,月份重置后,調(diào)用獲日歷主體方法就可獲取到上一個(gè)月和下一個(gè)月的日歷主體
選擇兩個(gè)日期選中,邏輯如下:
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)擊獲取的時(shí)候把當(dāng)前選中的對(duì)象傳遞下來(lái)
- 對(duì)象中有個(gè)字段是 2023-2-28 這樣的格式,這個(gè)格式,可以通過(guò) date 對(duì)象的 getTime 方法轉(zhuǎn)換成時(shí)間戳
- 如果第一次選中沒(méi)有值,或者 當(dāng)前選中的值小于 第一次選中的日期,那么存入第一次選中
- 如果第二次選中沒(méi)有紙,或者 當(dāng)前選中的值大于 第一次選中的日期,那么存入第二次選中
- 請(qǐng)注意:這里存入的時(shí)候,會(huì)自動(dòng)通過(guò)計(jì)算屬性把值轉(zhuǎn)換為時(shí)間戳
給兩個(gè)點(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]' } }
- 還是通過(guò)轉(zhuǎn)換時(shí)間戳的方式,去做對(duì)比
- 處于兩個(gè)選中日期中間的 格子 會(huì)返回個(gè)背景色
- 然后通過(guò)動(dòng)態(tài)class的方式插入顏色就可以了
- 演示如下:
尾聲
其實(shí)還有更多可深入研究的點(diǎn),比如:內(nèi)置對(duì)象 date 為啥能夠通過(guò)準(zhǔn)確獲取到當(dāng)前月的天數(shù)等,實(shí)現(xiàn)原理是啥,還有其它日期組件擴(kuò)展,比如props傳參,比如多類型(周日歷等)選擇等等。 但是最終考慮到這是vue3組件相關(guān)知識(shí)的梳理(傳參沒(méi)必要講,官方已經(jīng)寫(xiě)的很好了),以及其它周日歷等類型在代碼層面上來(lái)說(shuō),只需稍稍調(diào)整,思路還是這個(gè)思路,感覺(jué)沒(méi)啥必要去啰嗦,所以點(diǎn)到為止吧。
以上就是vue3基礎(chǔ)組件開(kāi)發(fā)-detePicker(日期選擇組件)的詳細(xì)內(nèi)容,更多關(guān)于vue3基礎(chǔ)組件detePicker的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
cesium開(kāi)發(fā)之如何在vue項(xiàng)目中使用cesium,使用離線地圖資源
這篇文章主要介紹了cesium開(kāi)發(fā)之如何在vue項(xiàng)目中使用cesium,使用離線地圖資源問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04vue中的數(shù)據(jù)格式化filters、formatter方式
這篇文章主要介紹了vue中的數(shù)據(jù)格式化filters、formatter方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07利用Vue3+Element?Plus封裝公共表格組件(帶源碼)
最近公司項(xiàng)目中頻繁會(huì)使用到table表格,而且前端技術(shù)這一塊也用到了vue3來(lái)開(kāi)發(fā),所以基于element plus table做了一個(gè)二次封裝的組件,這篇文章主要給大家介紹了關(guān)于利用Vue3+Element?Plus封裝公共表格組件的相關(guān)資料,需要的朋友可以參考下2023-11-11vue實(shí)現(xiàn)直播間點(diǎn)贊飄心效果的示例代碼
這篇文章主要介紹了vue實(shí)現(xiàn)直播間點(diǎn)贊飄心效果的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09vue中提示$index is not defined錯(cuò)誤的解決方式
這篇文章主要介紹了vue中提示$index is not defined錯(cuò)誤的解決方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09