vue自定义日历(含农历)

1.日历组件类

<template>
	<div v-if="showPicker" class="window-backdrop">
		<div class="window-wrapper">
			<div class="today-date-text">
				<div class="text-button" @click="cancle">取消</div>
				<img class="arrow-img" @click="toLastMonth" src="../assets/arrow_left.png">
				<div class="today-date">{{currentDateText}}</div>
				<img class="arrow-img" @click="toNextMonth" src="../assets/arrow_right.png">
				<div class="text-button" @click="confirm">确定</div>
			</div>
			<div class="week-wrapper">
				<div class="week-item">周日</div>
				<div class="week-item">周一</div>
				<div class="week-item">周二</div>
				<div class="week-item">周三</div>
				<div class="week-item">周四</div>
				<div class="week-item">周五</div>
				<div class="week-item">周六</div>
			</div>
			<div class="month-day-wrapper">
				<div @click="handleDay(day)" v-for="day in days"
					:class="day.selected ? 'day-item-actived' : 'day-item'">
					<div class="date-text">{{day.isToday ? '今天' : day.dateText}}</div>
					<div class="chinese-date-text">{{day.chineseDateText}}</div>
				</div>
				<div class="day-item" v-for="item in (7 - days.length % 7)"></div>
			</div>
		</div>
	 </div>
</template>

<script>
	import {
		toLunar
	} from './utils.js'
	export default {
		data() {
			return {
				days: [], // 当前月的所有日期的数据集合
				currentDateText: '', // 头部标题年月
				currentDate: '', // 初始化时为当前日期
				showPicker: false
			}
		},
		methods: {
			open() {
				this.showPicker = true
				this.initPicker()
			},
			confirm() {
				this.$emit('confirm', this.getSelectedDay())
			},
			cancle() {
				this.showPicker = false
			},
			getSelectedDay() {
				for (var i = 0; i < this.days.length; i++) {
					if (this.days[i].selected) return this.days[i]
				}
			},
			/**
			 * 日历点击事件,更新点击选中状态
			 * @param {Object} day
			 */
			handleDay(day) {
				if (!day.date) return
				for (var i = 0; i < this.days.length; i++) {
					this.days[i].selected = day.dateText === this.days[i].dateText
				}
				this.updateTitle(day)
			},
			/**
			 * 更新标题年月
			 * @param {Object} day
			 */
			updateTitle(day) {
				this.currentDateText = this.getDateText(day.date)
			},
			/**
			 * 下个月
			 */
			toLastMonth() {
				this.currentDate = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth() - 1, 1)
				this.days = this.getPickerData(this.currentDate)
				this.currentDateText = this.getDateText(this.currentDate)
			},
			/**
			 * 上个月
			 */
			toNextMonth() {
				this.currentDate = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth() + 1, 1)
				this.days = this.getPickerData(this.currentDate)
				this.currentDateText = this.getDateText(this.currentDate)
			},
			/**
			 * 设置日历标题
			 * @param {Object} day
			 */
			getDateText(day) {
				return day.getFullYear() + '年' + (day.getMonth() + 1) + '月'
			},
			/**
			 * 转换成周几
			 * @param {Object} day
			 */
			getWeekText(day) {
				let weekVal = day.getDay()
				let weekText = ''
				switch (weekVal) {
					case 0:
						weekText = '日'
						break
					case 1:
						weekText = '一'
						break
					case 2:
						weekText = '二'
						break
					case 3:
						weekText = '三'
						break
					case 4:
						weekText = '四'
						break
					case 5:
						weekText = '五'
						break
					case 6:
						weekText = '六'
						break

				}
				return '周' + weekText
			},
			/**
			 * 计算某个月的天数
			 * @param {Object} month
			 */
			getMonthDaysLength(day, month) {
				day.setMonth(month)
				day.setDate(0)
				return day.getDate()
			},
			/**
			 * 根据日期对象计算当前月份1日为星期几,
			 * 从而计算日期数组开始需要添加几个空数据
			 * @param {Object} day
			 */
			getEmptyDays(day) {
				return new Date(day.setDate(1)).getDay()
			},
			/**
			 * 根据传入的day对象获取当前月的所有日期数据
			 * @param {Object} day
			 */
			getPickerData(day) {
				let arr = []
				let emptyLength = this.getEmptyDays(day)
				for (var i = 0; i < emptyLength; i++) {
					arr.push({}) // 根据当前月份1号是星期几向往数组里添加空数据
				}
				let month = day.getMonth() + 1
				let daysLength = this.getMonthDaysLength(day, month) // 计算当前月份一共有多少天
				for (var i = 0; i < daysLength; i++) {
					let obj = {
						date: new Date(day.setDate(i + 1)), // Date类型的日期数据
						dateText: i + 1, // 用于显示的日期
						chineseDateText: toLunar(day.getFullYear(), month, i + 1).day, // 农历日期
						isToday: new Date().toDateString() === new Date(day.setDate(i + 1)).toDateString(), // 是否是今天
						selected: new Date().toDateString() === new Date(day.setDate(i + 1))
						.toDateString() // 设置今天为选中状态
					}
					arr.push(obj)
				}
				return arr
			},
			initPicker() {
				this.currentDate = new Date()
				this.currentDateText = this.getDateText(this.currentDate) // 初始化标题年月
				this.days = this.getPickerData(this.currentDate) // 默认当前日期初始化日历
			}
		}
	}
</script>

<style scoped lang="scss">
	* {
		box-sizing: border-box;
	}
	
	.window-backdrop{
		position: fixed;
		left: 0;
		top: 0;
		width: 100%;
		height: 100%;
		background: rgba(0, 0, 0, .6);
		display: flex;
		align-items: center;
		justify-content: center;
		z-index: 9999;
	}
	
	.window-wrapper{
		width: 80%;
		min-width: 300px;
		max-width: 800px;
		padding: 10px 15px;
		background: #fff;
		border-radius: 10px;
		border: 1px #000 solid;
	}

	.week-wrapper {
		display: flex;
		align-items: center;
		justify-content: space-between;
		height: 44px;
		font-weight: bold;

		.week-item {
			font-size: 14px;
			flex: 14.2857%;
			text-align: center;
		}
	}

	.today-date-text {
		display: flex;
		height: 50px;
		align-items: center;
		justify-content: space-between;
		line-height: 100%;
		padding: 0 20px;

		.text-button {
			font-size: 16px;
			color: #000;
		}

		.arrow-img {
			height: 30px;
			width: 30px;
		}

		.today-date {
			font-size: 18px;
			font-weight: bold;
		}
	}

	.month-day-wrapper {
		display: flex;
		flex-wrap: wrap;
		justify-content: space-between;

		.day-item,
		.day-item-actived {
			flex: 14.2857%;
			padding: 10px 0;
			margin-bottom: 5px;
			font-size: 13px;
			cursor: pointer;
			overflow: hidden;
			font-weight: bold;

			.date-text, .chinese-date-text {
				text-align: center;
			}
		}

		.day-item {
			color: #333;
		}

		.day-item-actived {
			color: #fff;
			background: #2875dd;
			border-radius: 5px;
		}
	}
</style>

2.引用页面类

<template>
	<div>
		<div @click="showDatePicker" style="margin-bottom: 20px;text-align: center;">打开日历</div>
		<date-picker ref="datePicker"></date-picker>
	</div>
</template>

<script>
	import datePicker from './date-picker.vue'
	export default {
		components: {
			datePicker
		},
		methods:{
			showDatePicker(){
				this.$refs.datePicker.open()
			}
		}
	}
</script>

<style scoped></style>

3.公历转农历工具类

var MIN_YEAR = 1891

var MAX_YEAR = 2100

var lunarInfo = [
	[0, 2, 9, 21936],
	[6, 1, 30, 9656],
	[0, 2, 17, 9584],
	[0, 2, 6, 21168],
	[5, 1, 26, 43344],
	[0, 2, 13, 59728],

	[0, 2, 2, 27296],
	[3, 1, 22, 44368],
	[0, 2, 10, 43856],
	[8, 1, 30, 19304],
	[0, 2, 19, 19168],
	[0, 2, 8, 42352],

	[5, 1, 29, 21096],
	[0, 2, 16, 53856],
	[0, 2, 4, 55632],
	[4, 1, 25, 27304],
	[0, 2, 13, 22176],
	[0, 2, 2, 39632],

	[2, 1, 22, 19176],
	[0, 2, 10, 19168],
	[6, 1, 30, 42200],
	[0, 2, 18, 42192],
	[0, 2, 6, 53840],
	[5, 1, 26, 54568],

	[0, 2, 14, 46400],
	[0, 2, 3, 54944],
	[2, 1, 23, 38608],
	[0, 2, 11, 38320],
	[7, 2, 1, 18872],
	[0, 2, 20, 18800],

	[0, 2, 8, 42160],
	[5, 1, 28, 45656],
	[0, 2, 16, 27216],
	[0, 2, 5, 27968],
	[4, 1, 24, 44456],
	[0, 2, 13, 11104],

	[0, 2, 2, 38256],
	[2, 1, 23, 18808],
	[0, 2, 10, 18800],
	[6, 1, 30, 25776],
	[0, 2, 17, 54432],
	[0, 2, 6, 59984],

	[5, 1, 26, 27976],
	[0, 2, 14, 23248],
	[0, 2, 4, 11104],
	[3, 1, 24, 37744],
	[0, 2, 11, 37600],
	[7, 1, 31, 51560],

	[0, 2, 19, 51536],
	[0, 2, 8, 54432],
	[6, 1, 27, 55888],
	[0, 2, 15, 46416],
	[0, 2, 5, 22176],
	[4, 1, 25, 43736],

	[0, 2, 13, 9680],
	[0, 2, 2, 37584],
	[2, 1, 22, 51544],
	[0, 2, 10, 43344],
	[7, 1, 29, 46248],
	[0, 2, 17, 27808],

	[0, 2, 6, 46416],
	[5, 1, 27, 21928],
	[0, 2, 14, 19872],
	[0, 2, 3, 42416],
	[3, 1, 24, 21176],
	[0, 2, 12, 21168],

	[8, 1, 31, 43344],
	[0, 2, 18, 59728],
	[0, 2, 8, 27296],
	[6, 1, 28, 44368],
	[0, 2, 15, 43856],
	[0, 2, 5, 19296],

	[4, 1, 25, 42352],
	[0, 2, 13, 42352],
	[0, 2, 2, 21088],
	[3, 1, 21, 59696],
	[0, 2, 9, 55632],
	[7, 1, 30, 23208],

	[0, 2, 17, 22176],
	[0, 2, 6, 38608],
	[5, 1, 27, 19176],
	[0, 2, 15, 19152],
	[0, 2, 3, 42192],
	[4, 1, 23, 53864],

	[0, 2, 11, 53840],
	[8, 1, 31, 54568],
	[0, 2, 18, 46400],
	[0, 2, 7, 46752],
	[6, 1, 28, 38608],
	[0, 2, 16, 38320],

	[0, 2, 5, 18864],
	[4, 1, 25, 42168],
	[0, 2, 13, 42160],
	[10, 2, 2, 45656],
	[0, 2, 20, 27216],
	[0, 2, 9, 27968],

	[6, 1, 29, 44448],
	[0, 2, 17, 43872],
	[0, 2, 6, 38256],
	[5, 1, 27, 18808],
	[0, 2, 15, 18800],
	[0, 2, 4, 25776],

	[3, 1, 23, 27216],
	[0, 2, 10, 59984],
	[8, 1, 31, 27432],
	[0, 2, 19, 23232],
	[0, 2, 7, 43872],
	[5, 1, 28, 37736],

	[0, 2, 16, 37600],
	[0, 2, 5, 51552],
	[4, 1, 24, 54440],
	[0, 2, 12, 54432],
	[0, 2, 1, 55888],
	[2, 1, 22, 23208],

	[0, 2, 9, 22176],
	[7, 1, 29, 43736],
	[0, 2, 18, 9680],
	[0, 2, 7, 37584],
	[5, 1, 26, 51544],
	[0, 2, 14, 43344],

	[0, 2, 3, 46240],
	[4, 1, 23, 46416],
	[0, 2, 10, 44368],
	[9, 1, 31, 21928],
	[0, 2, 19, 19360],
	[0, 2, 8, 42416],

	[6, 1, 28, 21176],
	[0, 2, 16, 21168],
	[0, 2, 5, 43312],
	[4, 1, 25, 29864],
	[0, 2, 12, 27296],
	[0, 2, 1, 44368],

	[2, 1, 22, 19880],
	[0, 2, 10, 19296],
	[6, 1, 29, 42352],
	[0, 2, 17, 42208],
	[0, 2, 6, 53856],
	[5, 1, 26, 59696],

	[0, 2, 13, 54576],
	[0, 2, 3, 23200],
	[3, 1, 23, 27472],
	[0, 2, 11, 38608],
	[11, 1, 31, 19176],
	[0, 2, 19, 19152],

	[0, 2, 8, 42192],
	[6, 1, 28, 53848],
	[0, 2, 15, 53840],
	[0, 2, 4, 54560],
	[5, 1, 24, 55968],
	[0, 2, 12, 46496],

	[0, 2, 1, 22224],
	[2, 1, 22, 19160],
	[0, 2, 10, 18864],
	[7, 1, 30, 42168],
	[0, 2, 17, 42160],
	[0, 2, 6, 43600],

	[5, 1, 26, 46376],
	[0, 2, 14, 27936],
	[0, 2, 2, 44448],
	[3, 1, 23, 21936],
	[0, 2, 11, 37744],
	[8, 2, 1, 18808],

	[0, 2, 19, 18800],
	[0, 2, 8, 25776],
	[6, 1, 28, 27216],
	[0, 2, 15, 59984],
	[0, 2, 4, 27424],
	[4, 1, 24, 43872],

	[0, 2, 12, 43744],
	[0, 2, 2, 37600],
	[3, 1, 21, 51568],
	[0, 2, 9, 51552],
	[7, 1, 29, 54440],
	[0, 2, 17, 54432],

	[0, 2, 5, 55888],
	[5, 1, 26, 23208],
	[0, 2, 14, 22176],
	[0, 2, 3, 42704],
	[4, 1, 23, 21224],
	[0, 2, 11, 21200],

	[8, 1, 31, 43352],
	[0, 2, 19, 43344],
	[0, 2, 7, 46240],
	[6, 1, 27, 46416],
	[0, 2, 15, 44368],
	[0, 2, 5, 21920],

	[4, 1, 24, 42448],
	[0, 2, 12, 42416],
	[0, 2, 2, 21168],
	[3, 1, 22, 43320],
	[0, 2, 9, 26928],
	[7, 1, 29, 29336],

	[0, 2, 17, 27296],
	[0, 2, 6, 44368],
	[5, 1, 26, 19880],
	[0, 2, 14, 19296],
	[0, 2, 3, 42352],
	[4, 1, 24, 21104],

	[0, 2, 10, 53856],
	[8, 1, 30, 59696],
	[0, 2, 18, 54560],
	[0, 2, 7, 55968],
	[6, 1, 27, 27472],
	[0, 2, 15, 22224],

	[0, 2, 5, 19168],
	[4, 1, 25, 42216],
	[0, 2, 12, 42192],
	[0, 2, 1, 53584],
	[2, 1, 21, 55592],
	[0, 2, 9, 54560]

]

//是否闰年

function isLeapYear(year) {
	return ((year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0))
}

//天干地支年

function lunarYear(year) {
	var gan = ['庚', '辛', '壬', '癸', '甲', '乙', '丙', '丁', '戊', '己']
	var	zhi = ['申', '酉', '戌', '亥', '子', '丑', '寅', '卯', '辰', '巳', '午', '未']
	var	str = year.toString().split("")
	return gan[str[3]] + zhi[year % 12]

}

//生肖年

function zodiacYear(year) {
	var zodiac = ['猴', '鸡', '狗', '猪', '鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊']
	return zodiac[year % 12]
}

//公历月份天数
//@param year 阳历-年
//@param month 阳历-月
function solarMonthDays(year, month) {
	var FebDays = isLeapYear(year) ? 29 : 28
	var monthHash = ['', 31, FebDays, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
	return monthHash[month]
}

//农历月份天数
function lunarMonthDays(year, month) {
	var monthData = lunarMonths(year)
	return monthData[month - 1]
}

//农历月份天数数组

function lunarMonths(year) {
	var yearData = lunarInfo[year - MIN_YEAR]
	var leapMonth = yearData[0]
	var bit = (+yearData[3]).toString(2)
	var months = []
	for (var i = 0; i < bit.length; i++) {
		months[i] = bit.substr(i, 1)
	}

	for (var k = 0, len = 16 - months.length; k < len; k++) {
		months.unshift('0')
	}
	months = months.slice(0, (leapMonth === 0 ? 12 : 13));
	for (var i = 0; i < months.length; i++) {
		months[i] = +months[i] + 29
	}
	return months
}

//农历每年的天数

//@param year 农历年份

function lunarYearDays(year) {
	var monthArray = lunarYearMonths(year)
	var len = monthArray.length
	return (monthArray[len - 1] === 0 ? monthArray[len - 2] : monthArray[len - 1])
}

//
function lunarYearMonths(year) {
	var monthData = lunarMonths(year)
	var res = []
	var temp = 0
	var yearData = lunarInfo[year - MIN_YEAR]
	var len = (yearData[0] === 0 ? 12 : 13)
	for (var i = 0; i < len; i++) {
		temp = 0
		for (var j = 0; j <= i; j++) {
			temp += monthData[j]
		}
		res.push(temp)
	}
	return res
}

//获取闰月

//@param year 农历年份

function leapMonth(year) {
	var yearData = lunarInfo[year - MIN_YEAR]
	return yearData[0]
}

//计算农历日期与正月初一相隔的天数
function betweenLunarDays(year, month, day) {
	var yearMonth = lunarMonths(year)
	var res = 0
	for (var i = 1; i < month; i++) {
		res += yearMonth[i - 1]
	}
	res += day - 1
	return res
}

//计算2个阳历日期之间的天数
//@param year 阳历年
//@param month
//@param day
//@param l_month 阴历正月对应的阳历月份
//@param l_day 阴历初一对应的阳历天

function betweenSolarDays(year, month, day, l_month, l_day) {
	var time1 = new Date(year + "-" + month + "-" + day).getTime()
	var	time2 = new Date(year + "-" + l_month + "-" + l_day).getTime()
	return Math.ceil((time1 - time2) / 24 / 3600 / 1000)
}

//根据距离正月初一的天数计算阴历日期
//@param year 阳历年
//@param between 天数
function lunarByBetween(year, between) {
	var lunarArray = {}
	var	yearMonth = []
	var	t = 0
	var	e = 0
	var	leapMonthVal = 0
	var	m = ''
	if (between === 0) {
		t = 1
		e = 1
		m = '正月'
	} else {
		year = between > 0 ? year : (year - 1)
		yearMonth = lunarYearMonths(year)
		leapMonthVal = leapMonth(year)
		between = between > 0 ? between : (lunarYearDays(year) + between)
		for (var i = 0; i < 13; i++) {
			if (between === yearMonth[i]) {
				t = i + 2
				e = 1
				break
			} else if (between < yearMonth[i]) {
				t = i + 1
				e = between - ((yearMonth[i - 1]) ? yearMonth[i - 1] : 0) + 1
				break
			}
		}
		m = (leapMonthVal !== 0 && t === leapMonthVal + 1) ?	('闰'.chineseMonth(t - 1)) : chineseMonth(((leapMonthVal !== 0 && leapMonthVal + 1 < t) ? (t - 1) : t))
	}
	lunarArray.lunarDate = year + '-' + t + '-' + e // 年月日
	lunarArray.repetMonth = leapMonthVal //闰几月
	lunarArray.yearType = lunarYear(year) // 天干地支年
	lunarArray.animal = zodiacYear(year) // 生肖年
	lunarArray.month = m // 月份
	lunarArray.day = chineseNumber(e, m) // 日
	return lunarArray
}

//中文月份
function chineseMonth(month) {
	var monthHash = ['', '正月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '冬月', '腊月']
	return monthHash[month]
}

//中文日期
function chineseNumber(num, month) {
	var dateHash = ['', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十']
	var res = ''
	if(num === 1){
		res = month
	}else if (num <= 10) {
		res = '初' + dateHash[num]
	} else if (num > 10 && num < 20) {
		res = '十' + dateHash[num - 10]
	} else if (num === 20) {
		res = "二十"
	} else if (num > 20 && num < 30) {
		res = "廿" + dateHash[num - 20]
	} else if (num === 30) {
		res = "三十"
	}
	return res
}

//转换农历
export function toLunar(year, month, day) {
	var yearData = lunarInfo[year - MIN_YEAR]
	if (year === MIN_YEAR && month <= 2 && day <= 9) {
		return [1891, 1, 1, '辛卯', '兔', '正月', '初一']
	}
	return lunarByBetween(year, betweenSolarDays(year, month, day, yearData[1], yearData[2]))
}

//转换公历
//@param year 阴历-年
//@param month 阴历-月,闰月处理:例如如果当年闰五月,那么第二个五月就传六月,相当于阴历有13个月
//@param date 阴历-日

export function toSolar(year, month, day) {
	var yearData = lunarInfo[year - MIN_YEAR]
	var between = betweenLunarDays(year, month, day)
	var ms = new Date(year + "-" + yearData[1] + "-" + yearData[2]).getTime()
	var s = ms + between * 24 * 60 * 60 * 1000
	var d = new Date()
	d.setTime(s)
	year = d.getFullYear()
	month = d.getMonth() + 1
	day = d.getDate()
	return [year, month, day]
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
我很抱歉,但是我无法直接通过引用内容查看具体的图片和代码。然而,根据你提供的引用信息,我可以告诉你关于vue日历自定义组件的一些信息。 根据引用,这个组件目录可以提供给你一些关于vue日历自定义组件的相关代码和文件。 根据引用,这个vue日历组件支持农历和假期展示,并且可以自定义可选择的日期范围。 根据引用,在组件中使用这个vue日历组件,你需要在main.js中引入它。组件默认情况下会显示一个自定义的左侧icon。某一个日期可以出现选中状态,也可以使用圆点模式来表示选中状态。你可以通过传递一个包active属性的数组对象来自定义某一天的数据。 总的来说,这个vue日历自定义组件提供了一些可定制化的功能,包括农历展示、假期展示以及可选择日期范围等。你可以根据你的需求在组件中进行相应的配置和使用。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [vue自定义日历组件](https://blog.csdn.net/weixin_38644883/article/details/88067612)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [vue日历组件,支持农历以及假期展示,可以自定义可选择日期范围](https://download.csdn.net/download/qq_29597215/86267518)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值