周计划获取周日历,react封装周日历组件
根据windows日历,获取当前周,以及当前周的前2周和后4周,共7周的日期范围
export function getFormatDate(serverDate) { let list = [] // 二维数组 let formatDate = function (date, days) { let year = date.getFullYear() let month = date.getMonth() + 1 let day = date.getDate() month = month < 10 ? '0' + month : month day = day < 10 ? '0' + day : day // let week = day === 7 ? 1 : parseInt(day / 7) + 1 return days + year + '.' + month + '.' + day } let getFormatDay = function (date) { let month = date.getMonth() + 1 month = month < 10 ? '0' + month : month let day = date.getDate() let week = day === 7 ? 1 : parseInt(day / 7) + 1 // 这里用Math.ceil()更合适 // return `${month}月第${week}周`
return `${month}月第${getWeekByDate(date)}周` } let addDate = function (date, n) { date.setDate(date.getDate() + n) return date } let setDate = function (date) { let week = date.getDay() === 0 ? 6 : date.getDay() - 1 date = addDate(date, week * -1) let arr = [] let day = getFormatDay(date) for (let i = 0; i < 7; i++) { arr.push(formatDate(i === 0 ? addDate(date, 0) : addDate(date, 1), day)) } // console.log(arr); list.push(arr) } let algo = [-2, -1, 0, 1, 2, 3, 4] for (let i = 0; i < algo.length; i++) { setDate( addDate(serverDate ? new Date(serverDate) : new Date(), algo[i] * 7) ) } // 处理成需要的结果 let result = [] list.forEach((item) => { item = item[0] + '-' + item[item.length - 1].substring( item[item.length - 1].length - 10, item[item.length - 1].length ) result.push(item) }) return result }
获取第几周

// 获取当前日期是当前月的第几周,月初不足一周归于上月最后一周 function getWeekByDate(str) { str = Date.parse(str) let date = new Date(str) let month = date.getMonth() + 1 let year = date.getFullYear() let dateN = new Date(str) //月份第一天 dateN = new Date(dateN.setDate(1)) let w1 = dateN.getDay() // 将字符串转为标准时间格式 let w = date.getDay() //周几 if (w === 0 && w1 != 0) { //当月第一天不是周天,当前日期是周天 w = 7 } let week = Math.ceil((date.getDate() + 6 - w) / 7) if (w1 != 1) //当月第一天不是周一 week = Math.ceil((date.getDate() + 6 - w) / 7) - 1 var cNum = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] if (week === 0) { //第0周归于上月的最后一周 month = date.getMonth() if (month === 0) { //跨年 month = 12 year = year - 1 } let dateLast = new Date(date) let dayLast = new Date(year, month, 0).getDate() let timestamp = new Date(year, month - 1, dayLast) w = new Date(timestamp).getDay() //周几 if (w === 0) { w = 7 } week = Math.ceil((timestamp.getDate() + 6 - w) / 7) - 1 } week = cNum[week] let time = year + '年' + month + '月第' + week + '周' // console.log(time) return week }
结果:
------------------------------------分隔线20220309---------------------------------
1、date.js
/* 周管理:获取格式化日历-start */ // 获取当前是xx月第xx周 function _getRankWeek(date: any) { const year = date.getFullYear() let month = date.getMonth() + 1 month = month < 10 ? '0' + month : month const day = date.getDate() const week = day === 7 ? 1 : Math.ceil(day / 7) return `${year}年${month}月第${_capital(week)}周` } function _capital(num: number): string { switch (num) { case 1: return '一' case 2: return '二' case 3: return '三' case 4: return '四' case 5: return '五' default: return ' ' } } // 将当前日期前进或后退n天 function _moveBackDate(date: any, n: number) { date.setDate(date.getDate() + n) return date } function _formatDate(date: any, days: string) { const year = date.getFullYear() let month = date.getMonth() + 1 let day = date.getDate() month = month < 10 ? '0' + month : month day = day < 10 ? '0' + day : day return days + year + '-' + month + '-' + day } // 获取本周内的7个日期 function _getDateByWeek(date: any) { const week = date.getDay() === 0 ? 6 + 2 : date.getDay() - 1 + 2 // +2 往前推2天 date = _moveBackDate(date, week * -1) const arr = [] for (let i = 0; i < 7; i++) { const fDate = i === 0 ? _moveBackDate(date, 0) : _moveBackDate(date, 1) const item = _formatDate(fDate, _getRankWeek(date)) arr.push(item) } return arr } // 判断两个日期间相差多少周 function _count(start:string, end:string) { const day1 = new Date(start) as any const day2 = new Date(end) as any return Math.ceil((day2 - day1) / (1000 * 60 * 60 * 24 * 7)) } export function getFormatDate(start?:string, end?:string) { const list = [] // 二维数组 let algo = [] // 2.3逻辑变更:如果传入了end,取start-end范围内的周;否则取原来的7周 if (end) { for (let i = 0, len = _count(start as string, end); i <= len; i++) { algo.push(i) } } else { algo = [-4, -3, -2, -1, 0, 1, 2] // 历史4周+当前周+未来2周 } for (let i = 0, len = algo.length; i < len; i++) { const date = start ? new Date(start) : new Date() const arr = _getDateByWeek(_moveBackDate(date, algo[i] * 7 + 2)) // +2 list.push(arr) } // 处理成需要的结果 const result = list.map((label:any, value) => { const startStr = label[0] const endStr = label[label.length - 1] const startdate = startStr.slice(11) const enddate = endStr.slice(endStr.length - 10, endStr.length) const start = startdate.slice(5).replace('-', '.') const end = enddate.slice(5).replace('-', '.') label = `${startStr.slice(0, 11)}(${start}-${end})` return { label, value, startdate, enddate } }) if (end && result[result.length - 1].startdate > end) result.pop() // 满足条件时删除最后一项 return result } // export function getFormatDate(serverDate?: any) { // const list = [] // 二维数组 // const algo = [-4, -3, -2, -1, 0, 1, 2] // 历史4周+当前周+未来2周 // for (let i = 0; i < algo.length; i++) { // const date = serverDate ? new Date(serverDate) : new Date() // const arr = _getDateByWeek(_moveBackDate(date, algo[i] * 7 + 2)) // +2 // list.push(arr) // } // // 处理成需要的结果 // const result = list.map((label: any, value) => { // const startStr = label[0] // const endStr = label[label.length - 1] // const startdate = startStr.slice(11) // const enddate = endStr.slice(endStr.length - 10, endStr.length) // const start = startdate.slice(5).replace('-', '.') // const end = enddate.slice(5).replace('-', '.') // label = `${startStr.slice(0, 11)}(${start}-${end})` // return { label, value, startdate, enddate } // }) // return result // } /* 周管理:获取格式化日历-end */
打印结果如下:
如果是跨年的边界值:getFormatDate('2023-01-08')
----2022-05-07修改入参,加入“归属周”的概念----:
①不传参数,默认以取今天的日期
②传一个参数('2022-01-01'),则取传入的参数
③传两个参数('2022-01-01', '2022-05-01'),则以这两个时间节点为边界找到其中所有的周,第一周的开始日期可能会小于参数一,最后一周的结束日期可能会大于参数二
2、vue实现
<template> <div id="app"> <el-button @click="prev">上一周</el-button> <el-select v-model="value" placeholder="请选择" width=100 size='medium'> <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </el-option> </el-select> <el-button @click="next">下一周</el-button> </div> </template> <script> import { getFormatDate } from '@/utils/date' export default { data() { return { options: [], value: 4 } }, methods: { prev() { if (this.value === 0) return console.log('已经是第一个了') this.value-- }, next() { const { options, value } = this if (value === options.length - 1) return console.log('已经是最后一个了') this.value++ } }, created() { const options = getFormatDate() this.options = options console.log(getFormatDate()) }, mounted() {}, components: {} } </script>
3、react实现
①WeekCalendar/index.tsx
/* 周日历组件 使用场景: 1、有初始值,有【上一周】【下一周】按钮 <WeekCalendar onChange={onWeekChange} isSelected hasToggleBtn /> 2、有初始值,没有【上一周】【下一周】按钮 <WeekCalendar onChange={onWeekChange} isSelected /> 3、没有初始值,没有【上一周】【下一周】按钮 <WeekCalendar onChange={onWeekChange} /> */ import React, { useState, useEffect } from 'react' import { Select, Button } from 'antd' import { getFormatDate } from '@/utils/utils' import styles from './index.less' interface WeekCalendarProps { onChange: (value: any, options?: any) => void isAllowClear?: boolean // 是否支持清除,默认:false isSelected?: boolean // 是否选中当前周,默认:true hasToggleBtn?: boolean // 是否有【上一周】【下一周】切换按钮,默认:false style?: Object isDisabled?: Boolean value?: any } const WeekCalendar: React.FC<WeekCalendarProps> = (Props: any) => { const { onChange, isAllowClear = false, isSelected = true, hasToggleBtn = false, style = {}, isDisabled, value } = Props const [prevDisabled, setPrevDisabled] = useState<boolean>(false) const [nextDisabled, setNextDisabled] = useState<boolean>(false) const [defaultValue, setDefaultValue] = useState<number>(4) // 默认选中下标4 const [selValue, setSelValue] = useState<number>() // 没有初始值时(isSelected === false),下拉框回显 const options = getFormatDate() // 根据下标获取元素 const getItem = (index: number) => options.find((item: object, i: number) => index === i) const handleChange = (index: number) => { if (index === undefined) return onChange('', {}) // 点击清空按钮,返回 {} if (isSelected) { setDefaultValue(index as number) } else { setSelValue(index as number) } const item = getItem(index as number) onChange(item?.startdate, item) setPrevDisabled(index === 0 ? true : false) setNextDisabled(index === options.length - 1 ? true : false) } useEffect(() => { if (isSelected) { const item = getItem(defaultValue) onChange(item?.startdate, item) } }, []) useEffect(() => { if (value) { const index = options.findIndex((item: any, i: number) => item.startdate === value) setSelValue(index) const item = getItem(index) onChange(item?.startdate, item) setDefaultValue(index) setPrevDisabled(index === 0 ? true : false) setNextDisabled(index === options.length - 1 ? true : false) } }, [value]) return ( <div className={styles.weekCalendar} style={{ display: 'flex', ...style }}> {hasToggleBtn ? ( <Button type="link" disabled={prevDisabled} onClick={handleChange.bind(this, defaultValue - 1)} > 上一周 </Button> ) : null} <Select onChange={(index) => handleChange(index as number)} disabled={isDisabled} options={options} defaultValue={isSelected ? defaultValue : selValue} value={selValue} key={defaultValue} allowClear={isAllowClear} placeholder="请选择日期范围" showSearch optionFilterProp="label" // 根据label过滤 /> {hasToggleBtn ? ( <Button type="link" disabled={nextDisabled} onClick={handleChange.bind(this, defaultValue + 1)} > 下一周 </Button> ) : null} </div> ) } WeekCalendar.defaultProps = { isDisabled: false } export default WeekCalendar
②使用
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 提示词工程——AI应用必不可少的技术
· 字符编码:从基础到乱码解决
· 地球OL攻略 —— 某应届生求职总结
2019-08-27 jQuery选择器