周计划获取周日历,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
      }
View Code

 

结果:

 

 

 

------------------------------------分隔线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

  ②使用

    

 

posted @ 2021-08-27 14:27  吴小明-  阅读(571)  评论(0编辑  收藏  举报