打造超酷的 React 迷你日历组件,只需几步!
现在市面上的组件库大多包含日历组件,那么它们具体是如何实现的呢?其实原理很简单,主要是通过使用Date对象的相关API。今天我们就来开发一个迷你版的日历组件。
你好,我是小白Coding日志,一个热爱技术的程序员。在这里,我分享自己在编程和技术世界中的学习心得和体会。希望我的文章能够给你带来一些灵感和帮助。欢迎来到我的博客,一起在技术的世界里探索前行吧!
前言
现在市面上的组件库大多包含日历组件,那么它们具体是如何实现的呢?其实原理很简单,主要是通过使用Date对象的相关API。今天我们就来开发一个迷你版的日历组件。
功能分析
实现一个迷你版的日历组件页面布局:
- Header部分:最中间的位置用于显示当前月份,左右两边分别设置切换上月和下月的按钮。
- 星期显示:Header的下方依次显示星期日到星期六。
- Body部分:显示当前月的天数。可以根据当前月份获取这个月有多少天,以及根据当前月1号获取是星期几,这样我们就能知道这个月从哪一天开始。
为日历组件提供默认值,即当前日历组件默认渲染为当前年份和月份。此外,还需提供一个onChange
方法,用于返回当前选中的日期。这样,一个基本的日历组件就完成了。
项目搭建
使用vite来创建一个React
项目
npm create vite@latest calendar-mini
选择React
然后选择JavaScript
切换到项目目录下cd calendar-mini
,运行npm install
安装依赖,npm run dev
把项目跑起来
编码
- 页面基本布局
删除App.jsx中App组件中的HTML
内容只保留下h1
标签,
import { useState } from 'react'
import './App.css'
function App() {
const [count, setCount] = useState(0)
return (
<>
<h1>mini日历组件📅</h1>
</>
)
}
export default App
新增一个Calendar组并提供基本样式,在App.jsx中导入组件
import React from 'react';
function Calendar() {
return (
<div className="calendar">
<div className="header">
<button><</button>
<div>2023 年 7 月</div>
<button>></button>
</div>
<div className="days">
<div className="day">日</div>
<div className="day">一</div>
<div className="day">二</div>
<div className="day">三</div>
<div className="day">四</div>
<div className="day">五</div>
<div className="day">六</div>
<div className="empty"></div>
<div className="empty"></div>
<div className="day">1</div>
<div className="day">2</div>
<div className="day">3</div>
<div className="day">4</div>
<div className="day">5</div>
<div className="day">6</div>
<div className="day">7</div>
<div className="day">8</div>
<div className="day">9</div>
<div className="day">10</div>
<div className="day">11</div>
<div className="day">12</div>
<div className="day">13</div>
<div className="day">14</div>
<div className="day">15</div>
<div className="day">16</div>
<div className="day">17</div>
<div className="day">18</div>
<div className="day">19</div>
<div className="day">20</div>
<div className="day">21</div>
<div className="day">22</div>
<div className="day">23</div>
<div className="day">24</div>
<div className="day">25</div>
<div className="day">26</div>
<div className="day">27</div>
<div className="day">28</div>
<div className="day">29</div>
<div className="day">30</div>
<div className="day">31</div>
</div>
</div>
);
}
export default Calendar;
.calendar {
border: 1px solid #aaa;
padding: 10px;
width: 300px;
height: 250px;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
height: 40px;
}
.days {
display: flex;
flex-wrap: wrap;
}
.empty, .day {
width: calc(100% / 7);
text-align: center;
line-height: 30px;
}
.day:hover {
background-color: #ccc;
cursor: pointer;
}
.day:hover, .selected {
background-color: #22a4f1;
cursor: pointer;
}
.m-10 {
margin: 10px 0;
}
import { useState } from 'react'
import './App.css'
import Calendar from './component/Calendar'
function App() {
return (
<>
<h1>mini日历组件📅</h1>
<Calendar />
</>
)
}
export default App
来看看效果👇
- 根据当前月份获取上月下月
结合useState
来获取日历组件的当前年份和月份,月份要加1因为月份是从0开始的
根据当前月获取上月下月
// 上月
const lastMonth = () =>{
setDate(new Date(date.getFullYear(), date.getMonth() - 1, 1))
}
// 下月
const nextMonth = () =>{
setDate(new Date(date.getFullYear(), date.getMonth() + 1, 1))
}
- 根据当前月份来渲染日期
const renderDays = () => {
const days = []
const daysCount = daysOfMonth(date.getFullYear(), date.getMonth())
const firstDays = firstDayOfMonth(date.getFullYear(), date.getMonth())
for(let i = 0; i<firstDays; i++){
days.push(<div key={`empty-${i}`} className="empty"></div>)
}
for(let i = 1; i<=daysCount; i++){
const handelClick = () =>{
const current = new Date(date.getFullYear(), date.getMonth(), i)
setDate(current)
props.onChange(current)
}
if(i === date.getDate()){
days.push(<div key={i} className="day selected" onClick={()=>handelClick()}>{i}</div>)
}else{
days.push(<div key={i} className="day" onClick={()=>handelClick()}>{i}</div>)
}
}
return days
}
定义一个renderDays函数用来渲染日期,提供一个days数组来动态的渲染日期,daysCount是当前月的天数,firstDays是当前月是从星期几开始的,先循环firstDays来添加空白项,再循环daysCount添加天,handelClick当点击某一天的时候选中并改变背景色。
- 添加默认值defaultValue和onChange方法
为Calendar
组件提供默认值
为state设置默认值
为Calendar
组件提供onChange方法,在点击某一天的时候调用onChange
回调将最新的值传递给onChange方法
Calendar.jsx组件全部代码
import { useState } from 'react';
function Calendar(props) {
const [date, setDate] = useState(new Date(props.defaultValue))
console.log(date.toLocaleDateString())
// 上月
const lastMonth = () =>{
setDate(new Date(date.getFullYear(), date.getMonth() - 1, 1))
}
// 下月
const nextMonth = () =>{
setDate(new Date(date.getFullYear(), date.getMonth() + 1, 1))
}
// 获取每个月有多少天
const daysOfMonth = (year, month) =>{
return new Date(year, month + 1, 0).getDate()
}
// 获取每个月第一天是星期几
const firstDayOfMonth = (year, month) =>{
return new Date(year, month, 1).getDay()
}
const renderDays = () => {
const days = []
const daysCount = daysOfMonth(date.getFullYear(), date.getMonth())
const firstDays = firstDayOfMonth(date.getFullYear(), date.getMonth())
for(let i = 0; i<firstDays; i++){
days.push(<div key={`empty-${i}`} className="empty"></div>)
}
for(let i = 1; i<=daysCount; i++){
const handelClick = () =>{
const current = new Date(date.getFullYear(), date.getMonth(), i)
setDate(current)
props.onChange(current)
}
if(i === date.getDate()){
days.push(<div key={i} className="day selected" onClick={()=>handelClick()}>{i}</div>)
}else{
days.push(<div key={i} className="day" onClick={()=>handelClick()}>{i}</div>)
}
}
return days
}
return (
<div className="calendar">
<div className="header">
<button onClick={lastMonth}><</button>
<div>{ date.getFullYear() } 年 { date.getMonth() + 1 } 月</div>
<button onClick={nextMonth}>></button>
</div>
<div className="days">
<div className="day">日</div>
<div className="day">一</div>
<div className="day">二</div>
<div className="day">三</div>
<div className="day">四</div>
<div className="day">五</div>
<div className="day">六</div>
{renderDays()}
</div>
</div>
);
}
export default Calendar;
App.jsx代码
import { useState } from 'react'
import './App.css'
import Calendar from './component/Calendar'
function App() {
return (
<>
<h1>mini日历组件📅</h1>
<Calendar defaultValue={'2024-07-19'} onChange={(date)=>{alert(date.toLocaleDateString())}} />
<Calendar defaultValue={'2024-10-04'} /
</>
)
}
export default App
以上就实现了一个mini版的日历组件😁
最后还是那句话:即使代码逻辑很简单,也值得记录下来。我的编程目标是避免重复造轮子!😊
如果觉得有用,就给我点个赞吧😁
探索更多有趣知识,欢迎关注我的微信公众号:小白Coding日志
,每天分享精彩内容,与你一同探寻知识的边界。一起开启知识新旅程!🚀📚
关注我的技术博客,探索前沿科技与实用开发技巧。一起携手走向代码的精彩世界!🚀💻 不错过每一篇精彩!
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)