资源描述:一款js自定义日期选择器,可自定义:日期格式、日历位置、指定日期屏蔽。日历弹出窗口显示当前月份的日期,以及上个月和下个月。用户可以通过点击日历弹出窗口来选择日期。
使用方法
function getWeekNumber(date) {
const firstDayOfTheYear = new Date(date.getFullYear(), 0, 1);
const pastDaysOfYear = (date.getTime() - firstDayOfTheYear.getTime()) / 86400000;
return Math.ceil((pastDaysOfYear + firstDayOfTheYear.getDay() + 1) / 7)
}
function isLeapYear(year) {
return year % 100 === 0 ? year % 400 === 0 : year % 4 === 0;
}
class Day {
constructor(date = null, lang = 'default') {
date = date ?? new Date();
this.Date = date;
this.date = date.getDate();
this.day = date.toLocaleString(lang, { weekday: 'long'});
this.dayNumber = date.getDay() + 1;
this.dayShort = date.toLocaleString(lang, { weekday: 'short'});
this.year = date.getFullYear();
this.yearShort = date.toLocaleString(lang, { year: '2-digit'});
this.month = date.toLocaleString(lang, { month: 'long'});
this.monthShort = date.toLocaleString(lang, { month: 'short'});
this.monthNumber = date.getMonth() + 1;
this.timestamp = date.getTime();
this.week = getWeekNumber(date);
}
get isToday() {
return this.isEqualTo(new Date());
}
isEqualTo(date) {
date = date instanceof Day ? date.Date : date;
return date.getDate() === this.date &&
date.getMonth() === this.monthNumber - 1 &&
date.getFullYear() === this.year;
}
format(formatStr) {
return formatStr
.replace(/\\bYYYY\\b/, this.year)
.replace(/\\bYYY\\b/, this.yearShort)
.replace(/\\bWW\\b/, this.week.toString().padStart(2, '0'))
.replace(/\\bW\\b/, this.week)
.replace(/\\bDDDD\\b/, this.day)
.replace(/\\bDDD\\b/, this.dayShort)
.replace(/\\bDD\\b/, this.date.toString().padStart(2, '0'))
.replace(/\\bD\\b/, this.date)
.replace(/\\bMMMM\\b/, this.month)
.replace(/\\bMMM\\b/, this.monthShort)
.replace(/\\bMM\\b/, this.monthNumber.toString().padStart(2, '0'))
.replace(/\\bM\\b/, this.monthNumber)
}
}
class Month {
constructor(date = null, lang = 'default') {
const day = new Day(date, lang);
const monthsSize = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
this.lang = lang;
this.name = day.month;
this.number = day.monthNumber;
this.year = day.year;
this.numberOfDays = monthsSize[this.number - 1];
if(this.number === 2) {
this.numberOfDays += isLeapYear(day.year) ? 1 : 0;
}
this[Symbol.iterator] = function* () {
let number = 1;
yield this.getDay(number);
while(number < this.numberOfDays) {
++number;
yield this.getDay(number);
}
}
}
getDay(date) {
return new Day(new Date(this.year, this.number - 1, date), this.lang);
}
}
class Calendar {
weekDays = Array.from({length: 7});
constructor(year = null, monthNumber = null, lang = 'default') {
this.today = new Day(null, lang);
this.year = year ?? this.today.year;
this.month = new Month(new Date(this.year, (monthNumber || this.today.monthNumber) - 1), lang);
this.lang = lang;
this[Symbol.iterator] = function* () {
let number = 1;
yield this.getMonth(number);
while(number < 12) {
++number;
yield this.getMonth(number);
}
}
this.weekDays.forEach((_, i) => {
const day = this.month.getDay(i + 1);
if(!this.weekDays.includes(day.day)) {
this.weekDays[day.dayNumber - 1] = day.day
}
})
}
get isLeapYear() {
return isLeapYear(this.year);
}
getMonth(monthNumber) {
return new Month(new Date(this.year, monthNumber - 1), this.lang);
}
getPreviousMonth() {
if(this.month.number === 1) {
return new Month(new Date(this.year - 1, 11), this.lang);
}
return new Month(new Date(this.year, this.month.number - 2), this.lang);
}
getNextMonth() {
if(this.month.number === 12) {
return new Month(new Date(this.year + 1, 0), this.lang);
}
return new Month(new Date(this.year, this.month.number + 2), this.lang);
}
goToDate(monthNumber, year) {
this.month = new Month(new Date(year, monthNumber - 1), this.lang);
this.year = year;
}
goToNextYear() {
this.year += 1;
this.month = new Month(new Date(this.year, 0), this.lang);
}
goToPreviousYear() {
this.year -= 1;
this.month = new Month(new Date(this.year, 11), this.lang);
}
goToNextMonth() {
if(this.month.number === 12) {
return this.goToNextYear();
}
this.month = new Month(new Date(this.year, (this.month.number + 1) - 1), this.lang);
}
goToPreviousMonth() {
if(this.month.number === 1) {
return this.goToPreviousYear();
}
this.month = new Month(new Date(this.year, (this.month.number - 1) - 1), this.lang);
}
}
class DatePicker extends HTMLElement {
format = 'MMM DD, YYYY';
position = 'bottom';
visible = false;
date = null;
mounted = false;
// elements
toggleButton = null;
calendarDropDown = null;
calendarDateElement = null;
calendarDaysContainer = null;
selectedDayElement = null;
constructor() {
super();
const lang = window.navigator.language;
const date = new Date(this.date ?? (this.getAttribute("date") || Date.now()));
this.shadow = this.attachShadow({mode: "open"});
this.date = new Day(date, lang);
this.calendar = new Calendar(this.date.year, this.date.monthNumber, lang);
this.format = this.getAttribute('format') || this.format;
this.position = DatePicker.position.includes(this.getAttribute('position'))
? this.getAttribute('position')
: this.position;
this.visible = this.getAttribute('visible') === ''
|| this.getAttribute('visible') === 'true'
|| this.visible;
this.render();
}
connectedCallback() {
this.mounted = true;
this.toggleButton = this.shadow.querySelector('.date-toggle');
this.calendarDropDown = this.shadow.querySelector('.calendar-dropdown');
const [prevBtn, calendarDateElement, nextButton] = this.calendarDropDown
.querySelector('.header').children;
this.calendarDateElement = calendarDateElement;
this.calendarDaysContainer = this.calendarDropDown.querySelector('.month-days');
this.toggleButton.addEventListener('click', () => this.toggleCalendar());
prevBtn.addEventListener('click', () => this.prevMonth());
nextButton.addEventListener('click', () => this.nextMonth());
document.addEventListener('click', (e) => this.handleClickOut(e));
this.renderCalendarDays();
}
attributeChangedCallback(name, oldValue, newValue) {
if(!this.mounted) return;
switch(name) {
case "date":
this.date = new Day(new Date(newValue));
this.calendar.goToDate(this.date.monthNumber, this.date.year);
this.renderCalendarDays();
this.updateToggleText();
break;
case "format":
this.format = newValue;
this.updateToggleText();
break;
case "visible":
this.visible = ['', 'true', 'false'].includes(newValue)
? newValue === '' || newValue === 'true'
: this.visible;
this.toggleCalendar(this.visible);
break;
case "position":
this.position = DatePicker.position.includes(newValue)
? newValue
: this.position;
this.calendarDropDown.className =
`calendar-dropdown ${this.visible ? 'visible' : ''} ${this.position}`;
break;
}
}
toggleCalendar(visible = null) {
if(visible === null) {
this.calendarDropDown.classList.toggle('visible');
} else if(visible) {
this.calendarDropDown.classList.add('visible');
} else {
this.calendarDropDown.classList.remove('visible');
}
this.visible = this.calendarDropDown.className.includes('visible');
if(this.visible) {
this.calendarDateElement.focus();
} else {
this.toggleButton.focus();
if(!this.isCurrentCalendarMonth()) {
this.calendar.goToDate(this.date.monthNumber, this.date.year);
this.renderCalendarDays();
}
}
}
prevMonth() {
this.calendar.goToPreviousMonth();
this.renderCalendarDays();
}
nextMonth() {
this.calendar.goToNextMonth();
this.renderCalendarDays();
}
updateHeaderText() {
this.calendarDateElement.textContent =
`${this.calendar.month.name}, ${this.calendar.year}`;
const monthYear = `${this.calendar.month.name}, ${this.calendar.year}`
this.calendarDateElement
.setAttribute('aria-label', `current month ${monthYear}`);
}
isSelectedDate(date) {
return date.date === this.date.date &&
date.monthNumber === this.date.monthNumber &&
date.year === this.date.year;
}
isCurrentCalendarMonth() {
return this.calendar.month.number === this.date.monthNumber &&
this.calendar.year === this.date.year;
}
selectDay(el, day) {
if(day.isEqualTo(this.date)) return;
this.date = day;
if(day.monthNumber !== this.calendar.month.number) {
this.prevMonth();
} else {
el.classList.add('selected');
this.selectedDayElement.classList.remove('selected');
this.selectedDayElement = el;
}
this.toggleCalendar();
this.updateToggleText();
}
handleClickOut(e) {
if(this.visible && (this !== e.target)) {
this.toggleCalendar(false);
}
}
getWeekDaysElementStrings() {
return this.calendar.weekDays
.map(weekDay => `<span>${weekDay.substring(0, 3)}</span>`)
.join('');
}
getMonthDaysGrid() {
const firstDayOfTheMonth = this.calendar.month.getDay(1);
const prevMonth = this.calendar.getPreviousMonth();
const totalLastMonthFinalDays = firstDayOfTheMonth.dayNumber - 1;
const totalDays = this.calendar.month.numberOfDays + totalLastMonthFinalDa
站长提示:
1. 苦力吧素材官方QQ群:
950875342
2. 平台上所有素材资源,需注册登录会员方能正常下载。
3. 会员用户积极反馈网站、素材资源BUG或错误问题,每次奖励
2K币。
4. PHP源码类素材,如需协助安装调试,或你有二次开发需求,可联系苦力吧客服。
5. 付费素材资源,需充值后方能下载,如有任何疑问可直接联系苦力吧客服