原生 JS 手写日历组件

相信很多初学者同学,在学完 Web Api 的时候自己手写案例的想法就会一发不可收拾,本文将为大家带来一个非常常见的组件手写,纯原生,文本前半部分为源码展示,后半部分为源码的讲解,逐步分析代码的逻辑,有耐心的可以观看后半部分,只需要效果的就可以直接复制源码

样式借鉴

源码文件获取

运行效果

在这里插入图片描述

源码展示

html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="./css/common.css">
  <link rel="stylesheet" href="./css/calendar-header.css">
  <link rel="stylesheet" href="./css/calendar-table.css">
  <link rel="stylesheet" href="https://at.alicdn.com/t/c/font_3918133_k2xnhhtzck.css">
  <title>原生手写日历组件</title>
</head>

<body>
  <div class="container">
    <div class="calendar-wrap">
      <div class="calendar-header">
        <div class="btn pre-year iconfont icon-left-arrows"></div>
        <div class="btn pre-month iconfont icon-left-arrow"></div>
        <div class="date-show"></div>
        <div class="btn next-month iconfont icon-right-arrow"></div>
        <div class="btn next-year iconfont icon-right-arrows"></div>
      </div>
      <table class="table-wrap">
        <thead>
        </thead>
        <tbody>
        </tbody>
      </table>
    </div>
  </div>
  <script src="./index.js"></script>
</body>

</html>

css

  1. common.css

    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    
    :root {
      --primary-color: #2495f5;
      --br: 8px;
      --bs: 5px 5px 5px #e0e0e6, -5px -5px 5px #fff;
      --bs-inset: 5px 5px 5px #e0e0e6 inset, -5px -5px 5px #fff inset;
    }
    
    .container {
      width: 100vw;
      height: 100vh;
      display: flex;
      justify-content: center;
      align-items: center;
      background-color: #edf0f5;
    }
    
  2. calendar-header.css

    .calendar-wrap {
      display: flex;
      flex-direction: column;
      padding: 15px;
      border-radius: var(--br);
      background-color: #edf0f5;
      box-shadow: var(--bs);
      cursor: pointer;
    }
    
    .calendar-header {
      display: flex;
      align-items: center;
    }
    
    .date-show {
      font-size: 20px;
      color: var(--primary-color);
      margin: 0 50px;
      font-weight: 600;
    }
    
    .btn {
      width: 45px;
      height: 45px;
      border-radius: var(--br);
      display: flex;
      justify-content: center;
      align-items: center;
      background-color: #edf0f5;
      box-shadow: var(--bs);
    }
    
    .btn:hover {
      box-shadow: var(--bs-inset);
    }
    
    .btn.iconfont {
      font-size: 18px;
      color: var(--primary-color);
      font-weight: bold;
    }
    
    .pre-month {
      margin-right: auto;
      margin-left: 10px;
    }
    
    .next-month {
      margin-left: auto;
      margin-right: 10px;
    }
    
  3. calendar-table.css

    .table-wrap {
      margin-top: 10px;
      border-spacing: 15px;
    }
    
    .table-wrap th {
      width: 50px;
      height: 50px;
      background-color: var(--primary-color);
      border-radius: var(--br);
      box-shadow: var(--bs);
      color: #fff;
      border: 2px solid #edf1f4;
    }
    
    .table-wrap td {
      font-weight: 500;
      font-size: 1.25rem;
      width: 50px;
      height: 50px;
      text-align: center;
      vertical-align: middle;
      background-color: #edf1f4;
      border-radius: var(--br);
      box-shadow: var(--bs);
      color: #777;
    }
    
    .table-wrap td.active.active {
      border: 2px solid #edf1f4;
      background-color: var(--primary-color);
      color: #fff;
      box-shadow: var(--bs);
    }
    
    .table-wrap td:hover {
      box-shadow: var(--bs-inset);
    }
    
    .table-wrap td.not-month {
      color: #ccc;
      box-shadow: var(--bs);
    }
    

js

/**
 * 获取指定月份的日历数据
 * @author coderjc <coderjc@qq.com>
 * @param {Number} year 年份(默认当前年份)
 * @param {Number} month 月份(默认当前月份)
 * @returns {Array} 返回一个指定月份的日历数组
 * @example
 * getCalendar(2023, 8) // 返回2023年8月的日历数组
 */
function getCalendar(year, month) {
	// 创建 date 对象实例
	const date = new Date()

	// 月份从 0 开始
	date.setFullYear(year)
	date.setMonth(month - 1)

	// 设置当月的第一天-即将日期设置为 1 号
	date.setDate(1)

	// 通过设置当月的第一天可以获取当前月的 1 号是周几
	const firstDay = date.getDay()

	// 获取当前月份的最大天数
	let curMaxMonthDays = getMaxDaysInMonth(year, month)

	// 获取上月的最大天数
	//  - 如果月份为1,则获取的上月天数为年份-1,月份12
	let preMonthDays = undefined
	if (month === 1) {
		preMonthDays = getMaxDaysInMonth(year - 1, 12)
	}
	// 否则正常获取
	else {
		preMonthDays = getMaxDaysInMonth(year, month - 1)
	}

	// 定义月数组
	const monthList = []

	// 本月初始天数值
	let count = 0

	// 下月初始天数值
	let nextCount = 0

	// 生成每月日历
	for (let i = 0; i < 6; i++) {
		// 生成每周的数据
		const weekList = new Array(7)
		monthList.push(weekList)
		// 当 i 为 0 表示是第一周的情况
		if (i === 0) {
			for (let j = firstDay; j < weekList.length; j++) {
				// 已知本月的第一天是周几,即可确定第一周的具体日期
				weekList[j] = {
					stage: 'cur',
					y: year,
					m: month,
					d: ++count
				}
			}
		}
		// 其余的也进行填值
		else {
			for (let j = 0; j < weekList.length; j++) {
				// 已知本月的第一天是周几,即可确定第一周的具体日期
				count++
				// 当这个天数超出本月最大天数的时候就填充下个月的天数
				if (count > curMaxMonthDays) {
					// 当月份数等于12时表示为下一年,则年份+1,月份重置为1
					if (month === 12) {
						weekList[j] = {
							stage: 'next',
							y: year + 1,
							m: 1,
							d: ++nextCount
						}
					}
					// 否则只执行月份+1
					else {
						weekList[j] = {
							stage: 'next',
							y: year,
							m: month + 1,
							d: ++nextCount
						}
					}
				}
				// 否则表示属于当前月
				else {
					weekList[j] = {
						stage: 'cur',
						y: year,
						m: month,
						d: count
					}
				}
			}
		}
	}

	// 填充第一周缺失的日期-即上月的末尾日期
	for (let i = firstDay - 1; i >= 0; i--) {
		let data = null
		// 如果当前月为1,则个月的填充数据年份需要-1,月份改为12
		if (month === 1) {
			data = {
				stage: 'pre',
				y: year - 1,
				m: 12,
				d: preMonthDays--
			}
		} else {
			data = {
				stage: 'pre',
				y: year,
				m: month - 1,
				d: preMonthDays--
			}
		}
		// 如果不为1,则只需要月份-1
		monthList[0][i] = data
	}

	return monthList
}

/**
 * 获取指定月份的最大天数
 * @author coderjc <coderjc@qq.com>
 * @param {Number} year 年份
 * @param {Number} month 月份
 * @returns {Number} 指定月份的当月最大天数
 * @example
 * getMaxDaysInMonth() // 返回一个指定月份的当月最大天数
 */
function getMaxDaysInMonth(year, month) {
	// 构造一个日期对象,将月份设置为所需的月份,日期为1日
	const date = new Date(year, month - 1, 1)
	// 将日期设置为下个月的第0天,即当前月的最后一天
	date.setMonth(date.getMonth() + 1, 0)
	// 获取日期对象的日期部分,即最大天数
	const maxDay = date.getDate()
	return maxDay
}

// 获取当前日期
function getToday() {
	const date = new Date()
	return {
		y: date.getFullYear(),
		m: date.getMonth() + 1,
		d: date.getDate()
	}
}

// 获取dom
const tableWrap = document.querySelector('.calendar-wrap .table-wrap')
const dateShow = document.querySelector('.date-show')
const theadDom = tableWrap.querySelector('thead')
const tbodyDom = tableWrap.querySelector('tbody')
const preYearBtn = document.querySelector('.pre-year')
const preMonthBtn = document.querySelector('.pre-month')
const nextYearBtn = document.querySelector('.next-year')
const nextMonthBtn = document.querySelector('.next-month')

// 获取当前日期
const currentYear = getToday().y
const currentMonth = getToday().m
const today = getToday().d

// 日历头部
const thList = ['日', '一', '二', '三', '四', '五', '六']

// 日历数据
const calendarList = getCalendar(currentYear, currentMonth)

// 创建标题
function createTitle(y, m) {
	dateShow.setAttribute('data-year', y)
	dateShow.setAttribute('data-month', m)
	dateShow.innerText = `${y}${m.toString().padStart(2, '0')}`
}

// 创建主体
function createTbody(list) {
	tbodyDom.innerHTML = ''
	list.forEach(row => {
		// 创建行
		const tr = document.createElement('tr')
		// 创建列
		row.forEach(col => {
			const td = document.createElement('td')
			col.stage !== 'cur' ? td.classList.add('not-month') : ''
			// 如果当前年月日相等且属于当前阶段时添加激活类名
			if (col.y === currentYear && col.m === currentMonth && col.d === today && col.stage === 'cur') {
				td.classList.add('active')
			}
			td.innerText = col.d
			tr.appendChild(td)
		})
		tbodyDom.appendChild(tr)
	})
}

// 创建头部
function createThead() {
	const tr = document.createElement('tr')
	thList.forEach(item => {
		const th = document.createElement('th')
		th.innerText = item
		tr.appendChild(th)
	})
	theadDom.appendChild(tr)
}

// 绑定事件
function bindEvent() {
	bindPreMonth()
	bindPreYear()
	bindNextMonth()
	bindNextYear()
}

// 上一月
function bindPreMonth() {
	preMonthBtn.addEventListener('click', function () {
		const y = +dateShow.getAttribute('data-year')
		const m = dateShow.getAttribute('data-month') - 1
		if (m <= 0) {
			dateShow.setAttribute('data-month', 12)
			preYearBtn.click()
			return
		}
		createTitle(y, m)
		createTbody(getCalendar(y, m))
	})
}

// 上一年
function bindPreYear() {
	preYearBtn.addEventListener('click', function () {
		const y = dateShow.getAttribute('data-year') - 1
		const m = +dateShow.getAttribute('data-month')
		createTitle(y, m)
		createTbody(getCalendar(y, m))
	})
}

// 下一月
function bindNextMonth() {
	nextMonthBtn.addEventListener('click', function () {
		const y = +dateShow.getAttribute('data-year')
		const m = +dateShow.getAttribute('data-month') + 1
		if (m >= 13) {
			dateShow.setAttribute('data-month', 1)
			nextYearBtn.click()
			return
		}
		createTitle(y, m)
		createTbody(getCalendar(y, m))
	})
}
// 下一年
function bindNextYear() {
	nextYearBtn.addEventListener('click', function () {
		const y = +dateShow.getAttribute('data-year') + 1
		const m = +dateShow.getAttribute('data-month')
		createTitle(y, m)
		createTbody(getCalendar(y, m))
	})
}

createTitle(currentYear, currentMonth)
createThead()
createTbody(calendarList)
bindEvent()

文件目录

在这里插入图片描述

源码分析

关于 html + css 的内容本文不在进行赘述,都是一些很简单的代码

步骤分析

  1. 如果想要实现一个日历组件,那么什么是最重要的呢,那肯定是这个一个日历的数据怎么生成,所以本案例的核心方法就是 getCalendar,这个方法的具体实现我们后续讲解
  2. 所以当我们得到这个数据之后就很简单了,只需要通过它生成对应的日历数据
  3. 生成数据后我们就要对按钮进行功能绑定,当然这些地方需要注意的就是临近边界值时的一些判断

###确定数据格式

  1. 我们先看一下方法的文档注释,如下:

    /**
     * 获取指定月份的日历数据
     * @author coderjc <coderjc@qq.com>
     * @param {Number} year 年份(默认当前年份)
     * @param {Number} month 月份(默认当前月份)
     * @returns {Array} 返回一个指定月份的日历数组
     * @example
     * getCalendar(2023, 8) // 返回2023年8月的日历数组
     */
    
  2. 通过这个文档注释我们就可以得出,需要接受两个参数,一个年份,一个月份,并返回指定日期的当月日历数据,好,那么这个日历数据应该是什么样式的呢,这里我们看一下 elemen-ui 的日历组件时什么样的,如图:

    在这里插入图片描述

  3. 这个图片我们先抛开上面的功能区域,只看显示的数据区域我们可以发现什么,是不是一个类似表格的数据啊,比如:

    在这里插入图片描述

  4. 所以如果按照这种数据推导的话,不看表头的话,实际需要生成的数据是不是只有数字部分啊,那么我们需要的是不是一个 六行七列的数据格式呢,但是好像我们无法找出可以直接表示这样的数据格式,那我们不妨换一个思考方法,我们首先创建一个数组,作为总的数组,然后其中的一行数据我们可以在创建一个数组,并放入开始创建的数组里面,那么我们现在的结构就变成了一个二维数组,如:[[]],那么这个一行的数组,里面应该放入什么了,每行都应该有 七列数据,所以我们可以确定,每一行里面应该放入七个数据,那现在我们可以得到一个这样的数组,如下:

    [[ null, null, null, null, null, null, null]]
    
  5. 现在表格的其中一行出来之后,我们剩下的 5 行也应该保持一直,所以我们最后确定的数据格式如下:

    [
        [ null, null, null, null, null, null, null],
        [ null, null, null, null, null, null, null],
        [ null, null, null, null, null, null, null],
        [ null, null, null, null, null, null, null],
        [ null, null, null, null, null, null, null],
        [ null, null, null, null, null, null, null]
    ]
    
  6. 那么第一步我们就可以写一段 for 循环来实现这段数据的生成,如下:

    // 存储日历数据
    const monthList = []
    
    for (let i = 0; i < 6; i++) {
    	// 生成每周的数据
    	const weekList = new Array(7)
    	monthList.push(weekList)
    }
    
  7. 此时我们可以打印看一下数据,如图:

    在这里插入图片描述

  8. 此时因为没有填充数据,显示为空是正常的

基础填充数据

  1. 有了基本的数据格式之后,我们就要考虑填充,怎么填充又陷入了一个难题,填充本月的日历,第一步是什么,是不是确定本月的第一天是星期几呢,当我们得出是周几之后,是不是就可以在第一个行数组中开始进行填充呢

  2. 如何获取本月的第一天是周几,如下:

    // 创建 date 对象实例
    const date = new Date()
    
    // 设置当月的第一天-即将日期设置为 1 号
    date.setDate(1)
    
    // 通过设置当月的第一天可以获取当前月的 1 号是周几
    const firstDay = date.getDay()
    
  3. 结果如图:

    在这里插入图片描述

  4. 这个 5 是索引,索引从 0 开始,依次为 [‘日’, ‘一’, ‘二’, ‘三’, ‘四’, ‘五’, ‘六’],所以这个数组的索引为 5 的数据就是 周五

  5. 本月第一天为 周五,当我们获取到第一天之后我们就可以确定本月第一天,所以我们第一行数据第五项为本月的 1 号,而确定一号之后,后面的数据我们是否也可以确定了呢,每项 1 开始自增,是不是就是我们需要的数据呢,而没一行也是数组,所以我们需要给每一行的数组进行赋值数据的时候,我们可以采用双重 for 循环的方法,代码如下:

    function getCalendar(year, month) {
    	const date = new Date()
    
    	// 月份从 0 开始,所以传递进来的月份值我们需要 - 1
    	date.setFullYear(year)
    	date.setMonth(month - 1)
    
    	date.setDate(1)
    
    	const firstDay = date.getDay()
    	console.log(firstDay)
    
    	const monthList = []
    
    	// 定义初始数据
    	let count = 0
    
    	for (let i = 0; i < 6; i++) {
    		const weekList = new Array(7)
    		monthList.push(weekList)
    		// 当 i 为 0 表示是第一行的数组
    		if (i === 0) {
    			// j 的初始值为本月第一天在一周中的索引值
    			for (let j = firstDay; j < weekList.length; j++) {
    				weekList[j] = ++count
    			}
    		}
    		// 其他后续数据我们一样直接自增填充
    		else {
    			for (let j = firstDay; j < weekList.length; j++) {
    				weekList[j] = ++count
    			}
    		}
    	}
    	console.log(monthList)
    }
    
  6. 此时我们在看一下生成的数据,如图:

    在这里插入图片描述

  7. 看到这个图,是不是一个日历的数据填充就已经初具规模了呢,现在我们还需要填充什么,是不是要做一下判断啊,判断当前超出本月最大天数的时候就再次从 1 开始替换成下月的数据,所以我们就要知道本月的最大天数,代码比较简单,如下:

    /**
     * 获取指定月份的最大天数
     * @author coderjc <coderjc@qq.com>
     * @param {Number} year 年份
     * @param {Number} month 月份
     * @returns {Number} 指定月份的当月最大天数
     * @example
     * getMaxDaysInMonth() // 返回一个指定月份的当月最大天数
     */
    function getMaxDaysInMonth(year, month) {
    	// 构造一个日期对象,将月份设置为所需的月份,日期为1日
    	const date = new Date(year, month - 1, 1)
    	// 将日期设置为下个月的第0天,即当前月的最后一天
    	date.setMonth(date.getMonth() + 1, 0)
    	// 获取日期对象的日期部分,即最大天数
    	const maxDay = date.getDate()
    	return maxDay
    }
    
  8. 所以当我们可以得知本月最大天数的时候,就可以对超出部分的数据进行处理,如下:

    function getCalendar(year, month) {
    	const date = new Date()
    
    	date.setFullYear(year)
    	date.setMonth(month - 1)
    
    	date.setDate(1)
    
    	const firstDay = date.getDay()
    
    	// 获取当前月份的最大天数
    	let curMaxMonthDays = getMaxDaysInMonth(year, month)
    
    	const monthList = []
    
    	let count = 0
    	// 定义下月日期起始值
    	let nextCount = 0
    
    	for (let i = 0; i < 6; i++) {
    		const weekList = new Array(7)
    		monthList.push(weekList)
    		if (i === 0) {
    			for (let j = firstDay; j < weekList.length; j++) {
    				weekList[j] = ++count
    			}
    		} else {
    			for (let j = 0; j < weekList.length; j++) {
    				// 提前自增
    				count++
    				// 检测如果 count 大于 本月天数最大值,就重置
    				weekList[j] = count > curMaxMonthDays ? ++nextCount : count
    			}
    		}
    	}
    	console.log(monthList)
    }
    
    function getMaxDaysInMonth(year, month) {
    	const date = new Date(year, month - 1, 1)
    	date.setMonth(date.getMonth() + 1, 0)
    	const maxDay = date.getDate()
    	return maxDay
    }
    
  9. 结果如图:

    在这里插入图片描述

  10. 现在是不是还有上个月那部分数据没有搞定啊,这个也简单,我们需要得知的是上个月的最大天数,然后使用最大天数值递减,填满第一行数组的空缺部分即可,那怎么才能实现呢,代码如下:

    function getCalendar(year, month) {
    	const date = new Date()
    
    	date.setFullYear(year)
    	date.setMonth(month - 1)
    
    	date.setDate(1)
    
    	const firstDay = date.getDay()
    
    	let curMaxMonthDays = getMaxDaysInMonth(year, month)
        
    	// 获取上月的最大天数
    	let preMonthDays = getMaxDaysInMonth(year, month - 1)
    
    	const monthList = []
    
    	let count = 0
    	let nextCount = 0
    
    	for (let i = 0; i < 6; i++) {
    		const weekList = new Array(7)
    		monthList.push(weekList)
    		if (i === 0) {
    			for (let j = firstDay; j < weekList.length; j++) {
    				weekList[j] = ++count
    			}
    		} else {
    			for (let j = 0; j < weekList.length; j++) {
    				count++
    				weekList[j] = count > curMaxMonthDays ? ++nextCount : count
    			}
    		}
    	}
    
    	// 填充第一周缺失的日期-即上月的末尾日期
    	// 为什么要使用(本月第一周的索引)作为 i 的起始值呢?
    	//  - 假设上月的数据是 31,如果正常循环递减,那么得到的就是 31、30、29、28、27
    	//  - 如果使用这个数据,从索引第一行的索引开始添加那么结果就是 [31,30,29,28,27,1,2]
    	//  - 这显然是不符合我们期望的数据的,索引我们还是递减,但是加入的索引顺序就应该是反的
    	//  - 本月的第一天索引是 5,所以反着添加的话,就应该是索引 4 开始
    	for (let i = firstDay - 1; i >= 0; i--) {
    		monthList[0][i] = preMonthDays--
    	}
    	console.log(monthList)
    }
    
    function getMaxDaysInMonth(year, month) {
    	const date = new Date(year, month - 1, 1)
    	date.setMonth(date.getMonth() + 1, 0)
    	const maxDay = date.getDate()
    	return maxDay
    }
    
  11. 结果如图:

    在这里插入图片描述

  12. 此时我们就完成了日历数据的初步填充

进阶数据填充

  1. 上面我们已经获得了基础的日历数据,但是这个方法还有待优化,如果需要做到日历切换,我们已经够了,只需要通过方法改变日期即可,不敢我们如果想要在样式上,让不属于这个月的数据置灰,就需要能够做得出区分,所以我们需要将数据包装成为一个对象,即通过一个布尔值来确定当前的日期是否属于本月的,不过在我的示例中,对这个对象做了一些比较全面的数据,它会包含年、月、日、类型(cur next pre) cur 表示是当前月,next 是下一月,pre 为上月,但是如果只是为了实现样式的效果,单纯使用一个布尔值即可

  2. 这一部分的代码比较简单,只是对于临界值的一些判断,做出对应的改变,具体的解析在代码中有注释,如下:

    function getCalendar(year, month) {
    	// 创建 date 对象实例
    	const date = new Date()
    
    	// 月份从 0 开始
    	date.setFullYear(year)
    	date.setMonth(month - 1)
    
    	// 设置当月的第一天-即将日期设置为 1 号
    	date.setDate(1)
    
    	// 通过设置当月的第一天可以获取当前月的 1 号是周几
    	const firstDay = date.getDay()
    
    	// 获取当前月份的最大天数
    	let curMaxMonthDays = getMaxDaysInMonth(year, month)
    
    	// 获取上月的最大天数
    	//  - 如果月份为1,则获取的上月天数为年份-1,月份12
    	let preMonthDays = undefined
    	if (month === 1) {
    		preMonthDays = getMaxDaysInMonth(year - 1, 12)
    	}
    	// 否则正常获取
    	else {
    		preMonthDays = getMaxDaysInMonth(year, month - 1)
    	}
    
    	// 定义月数组
    	const monthList = []
    
    	// 本月初始天数值
    	let count = 0
    
    	// 下月初始天数值
    	let nextCount = 0
    
    	// 生成每月日历
    	for (let i = 0; i < 6; i++) {
    		// 生成每周的数据
    		const weekList = new Array(7)
    		monthList.push(weekList)
    		// 当 i 为 0 表示是第一周的情况
    		if (i === 0) {
    			for (let j = firstDay; j < weekList.length; j++) {
    				// 已知本月的第一天是周几,即可确定第一周的具体日期
    				weekList[j] = {
    					stage: 'cur',
    					y: year,
    					m: month,
    					d: ++count
    				}
    			}
    		}
    		// 其余的也进行填值
    		else {
    			for (let j = 0; j < weekList.length; j++) {
    				// 已知本月的第一天是周几,即可确定第一周的具体日期
    				count++
    				// 当这个天数超出本月最大天数的时候就填充下个月的天数
    				if (count > curMaxMonthDays) {
    					// 当月份数等于12时表示为下一年,则年份+1,月份重置为1
    					if (month === 12) {
    						weekList[j] = {
    							stage: 'next',
    							y: year + 1,
    							m: 1,
    							d: ++nextCount
    						}
    					}
    					// 否则只执行月份+1
    					else {
    						weekList[j] = {
    							stage: 'next',
    							y: year,
    							m: month + 1,
    							d: ++nextCount
    						}
    					}
    				}
    				// 否则表示属于当前月
    				else {
    					weekList[j] = {
    						stage: 'cur',
    						y: year,
    						m: month,
    						d: count
    					}
    				}
    			}
    		}
    	}
    
    	// 填充第一周缺失的日期-即上月的末尾日期
    	for (let i = firstDay - 1; i >= 0; i--) {
    		let data = null
    		// 如果当前月为1,则个月的填充数据年份需要-1,月份改为12
    		if (month === 1) {
    			data = {
    				stage: 'pre',
    				y: year - 1,
    				m: 12,
    				d: preMonthDays--
    			}
    		} 
            // 如果不为1,则只需要月份-1
            else {
    			data = {
    				stage: 'pre',
    				y: year,
    				m: month - 1,
    				d: preMonthDays--
    			}
    		}
    		monthList[0][i] = data
    	}
    
    	return monthList
    }
    
  3. 结果如图:

    在这里插入图片描述

结语

并不是忘记了解析后面的代码,后面的代码只是简单的获取dom,根据条件生成元素,通过方法来修改年月值,再次调用 getCalendar方法生成新的 dom 在渲染即可,所以就不用解析了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值