start

  • This article purely rely on their own ideas to write, if there are similar, also is not plagiarism.
  • Before reading this article, you need to know a bit about TS, VUe3, and JSX syntax. 😯 and moment grammar.

The expected effect or the actual effect is exactly the same 😄

  • Envisioned effect Element-UI calendar component

  • The actual effect

implementation

  • The implementation of calendar component, with the help of moement. Js greatly simplifies the calculation process, but also reduces a lot of code. Can be said to greatly reduce the difficulty of implementation.
  • This article is intended as an exercise only. Please correct any errors.
  • Calendar this everybody knows, laborious introduce the use of the scene that the personal feel is not useful, you met naturally can think of.

Calculating dates – which dates the page displays – is the primary function

  • There are actually two types of this: the one where the page only shows the current month, or the one in the picture above, which shows a week per line, which is a little bit more complicated. Why more complicated?
    • To get the whole month, you just get the number of days of the month and then you add them up from the first to get all the days of the month.
    • With a weekly one-line display, you need to get the day of the week for the first day of the current month and then calculate how many days forward to show it.

interface obj {
  [propName: string]: string | number;
}

// The date of the week is translated into Chinese
const weekList = ['Sunday'.'Monday'.'on Tuesday'.'on Wednesday'.'on Thursday.'on Friday'.'on Saturday]
let listOfDatesOfTheMonth: Array<obj> = reactive([])

// Calculate the number of days the calendar needs to display
const generatedDate = (val? : string) = > {
  // Obtain is a few months
  const month = moment(val || new Date()).format('YYYY-MM')
  // Obtain the day of the week for the first day of the month
  const whichDay = moment(month).startOf('month').weekday()
  // Calculate the start date from 7 minus the day of the week (0123456, where 0 represents Sunday)
  const startDate = moment(moment(month).subtract(7 - whichDay, 'days')).format('YYYY-MM-DD')

  // Organize the data
  // [...Array(42).keys()] [...Array(42).keys()] Because some of the months are 28 or 30, 31, 35, some of the months are not fully displayed.
  listOfDatesOfTheMonth = [...Array(42).keys()].reduce((acc:Array<obj>, val) = > {
    // Get the date of presentation
    const date = moment(startDate).add(val + 1.'days').format('YYYY-MM-DD')
    // The split date is used to get the number such as 123456
    const dateList = date.split(The '-')
    // Get the day of the week
    const week = moment(date).weekday()

    // Put the required data into an array
    acc.push({ index: val + 1.date: date, day: dateList[dateList.length - 1].week: weekList[week] })
    // Return an array to reduce
    return acc
  }, [])
  console.log(listOfDatesOfTheMonth)

  getDateItemList()
}
Copy the code

Last month or the same day or the next month

  • To implement this, we need to record the current month, and then add a month minus a month, and then just new Date()?
// Current day Selects the day
const currentDate = ref(moment().format('YYYY-MM-DD'))
/ / the current month
const currentMonth = ref(moment().format('YYYY-MM'))

// Last month, next month, current month
const changeMonth = (type: string) = > {
  // Set the date. This is used to recreate the display data when clicking on a month other than the current month
  if (type === 'setDate') {
    currentMonth.value = moment(currentDate.value).format('YYYY-MM')}/ / today
  if (type === 'today') {
    currentMonth.value = moment().format('YYYY-MM')}/ / next month
  if (type === 'nextMonth') {
    currentMonth.value = moment(currentMonth.value).add(1.'month').format('YYYY-MM')}/ / last month
  if (type === 'lastMonth') {
    currentMonth.value = moment(currentMonth.value).subtract(1.'month').format('YYYY-MM')
  }

  currentDate.value = moment(currentMonth.value).format('YYYY-MM-DD')
  generatedDate(currentMonth.value)
}
Copy the code

Click on the calendar date

  • This has two effects: one is to add a background color to the selected date and determine if the current date is equal to the selected date and add a class implementation
  • Click on a date other than the current month to regenerate the data.
// Set the selected day for the current day
const setCurrentDate = (date:string) = > {
  currentDate.value = date
  // Regenerate the calendar with different months
  if (date.indexOf(currentMonth.value) === -1) {
    changeMonth('setDate')}}// Get the daily Settings style and action
let dateItemList: JSX.Element[] = []
const getDateItemList = () = > {
  dateItemList = listOfDatesOfTheMonth.map(item= > {
    Date can be a string or an array. See obj's definition
    const isCurrentMonth = String(item.date).indexOf(currentMonth.value) === -1
    // Calculate the bound class
    const className = `dateItem ${isCurrentMonth ? ' ' : 'currentMonth'} ${currentDate.value === item.date ? 'currentDate' : ' '}`
    return <div onClick={()= > { setCurrentDate(item.date + '') }} class={className}>{parseInt(item.day + '') }</div>})}Copy the code

The final code

import { defineComponent, ref, reactive, onMounted, watch } from 'vue'
import './indenx.scss'
import moment from 'moment'

export default defineComponent({
  name: 'calender',
  setup () {
    interface obj {
      [propName: string]: string | number;
    }

    // Current day Selects the day
    const currentDate = ref(moment().format('YYYY-MM-DD'))
    / / the current month
    const currentMonth = ref(moment().format('YYYY-MM'))

    const weekList = ['Sunday'.'Monday'.'on Tuesday'.'on Wednesday'.'on Thursday.'on Friday'.'on Saturday]
    let listOfDatesOfTheMonth: Array<obj> = reactive([])

    // Calculate the number of days the calendar needs to display
    const generatedDate = (val? : string) = > {
      // Obtain is a few months
      const month = moment(val || new Date()).format('YYYY-MM')
      // Obtain the day of the week for the first day of the month
      const whichDay = moment(month).startOf('month').weekday()
      // Calculate the start date from 7 minus the day of the week (0123456, where 0 represents Sunday)
      const startDate = moment(moment(month).subtract(7 - whichDay, 'days')).format('YYYY-MM-DD')

      // Organize the data
      // [...Array(42).keys()] [...Array(42).keys()] Because some of the months are 28 or 30, 31, 35, some of the months are not fully displayed.
      listOfDatesOfTheMonth = [...Array(42).keys()].reduce((acc:Array<obj>, val) = > {
        // Get the date of presentation
        const date = moment(startDate).add(val + 1.'days').format('YYYY-MM-DD')
        // The split date is used to get the number such as 123456
        const dateList = date.split(The '-')
        // Get the day of the week
        const week = moment(date).weekday()

        // Put the required data into an array
        acc.push({ index: val + 1.date: date, day: dateList[dateList.length - 1].week: weekList[week] })
        // Return an array to reduce
        return acc
      }, [])
      console.log(listOfDatesOfTheMonth)

      getDateItemList()
    }

    onMounted(() = > {
      // Initialize the calendar to default the current month
      changeMonth('today')})// Listen for the current selected date to update the view
    watch(currentDate, () = > {
      getDateItemList()
    })

    // Get the daily Settings style and action
    let dateItemList: JSX.Element[] = []
    const getDateItemList = () = > {
      dateItemList = listOfDatesOfTheMonth.map(item= > {
        Date can be a string or an array. See obj's definition
        const isCurrentMonth = String(item.date).indexOf(currentMonth.value) === -1
        // Calculate the bound class
        const className = `dateItem ${isCurrentMonth ? ' ' : 'currentMonth'} ${currentDate.value === item.date ? 'currentDate' : ' '}`
        return <div onClick={()= > { setCurrentDate(item.date + '') }} class={className}>{parseInt(item.day + '') }</div>})}// Last month, next month, current month
    const changeMonth = (type: string) = > {
      / / today
      if (type === 'setDate') {
        currentMonth.value = moment(currentDate.value).format('YYYY-MM')}/ / today
      if (type === 'today') {
        currentMonth.value = moment().format('YYYY-MM')}/ / next month
      if (type === 'nextMonth') {
        currentMonth.value = moment(currentMonth.value).add(1.'month').format('YYYY-MM')}/ / last month
      if (type === 'lastMonth') {
        currentMonth.value = moment(currentMonth.value).subtract(1.'month').format('YYYY-MM')
      }

      currentDate.value = moment(currentMonth.value).format('YYYY-MM-DD')
      generatedDate(currentMonth.value)
    }

    // Set the selected day for the current day
    const setCurrentDate = (date:string) = > {
      currentDate.value = date
      // Regenerate the calendar with different months
      if (date.indexOf(currentMonth.value) === -1) {
        changeMonth('setDate')}}// Header week list
    const weekItemList = weekList.map(item= > {
      return <div class='dateItem'>{item}</div>
    })

    return () = > (
      <div class='calendar-box'>
        {currentDate.value}
        <div class='header'>
          <p>{currentMonth.value}</p>
          <div class='operate'>
            <p onClick={()= >{changeMonth('lastMonth')}}> lastMonth</p>
            <p onClick={()= >{changeMonth('today')}}> Today</p>
            <p onClick={()= >{changeMonth('nextMonth')}}> nextMonth</p>
          </div>
        </div>
        <div class='weekBox'>{weekItemList}</div>
        <div class='dateItemBox'>{dateItemList}</div>
      </div>)}})Copy the code
// indenx.scss// Calendar component.calendar-box {
  width: 430px;
  border: 1px solid #ebeef5;

  .header {
    display: flex;
    justify-content: space-between;
    align-content: center;
    padding: 5px;
    border-bottom: 1px solid #ebeef5;

    .operate {
      display: flex;
      justify-content: flex-end;

      p {
        padding: 5px 10px;
        margin-left: 5px;
        border-radius: 2px;
        border: 1px solid #ebeef5;
        cursor: pointer;
      }

      p:hover {
        background: #f2f8fe; }}}.dateItemBox , .weekBox {
    width: 100%;
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
    .dateItem {
      color: gray;
      width: calc(100% / 7);
      height: 40px;
      border: 1px solid #ebeef5;
      cursor: default;
    }

    .dateItem:nth-of-type(7n) {
      margin-right: 0;
    }

    .dateItem:hover{
      background: #f2f8fe;
    }


    .currentMonth{
      color: # 303133;
    }

    .currentDate{
      background: #f2f8fe; }}.weekBox{
    .dateItem{
      text-align: center;
      line-height: 40px;
      border: none; }}}Copy the code