От автора: некоторое время назад в проекте Angular мне нужно было отобразить полноэкранный календарь, такой как в outlook. Поэтому, как обычный ленивый разработчик, я начал искать в Интернете пакет NPM, который мог бы сделать эту работу.
К моему удивлению, я не нашел ничего, что могло бы покрыть мои потребности на 100%, поэтому я построил свой собственный календарь! Это конечный результат:
PS: Пожалуйста, будьте снисходительны ко мне, HTML и CSS не являются моей сильной стороной.
Вот история того, как я это сделал.
1-й давайте создадим компонент Angular
Это наша отправная точка, компонент Angular и массив, который будет содержать дни, для которых будет отображаться календарь.
JavaScript @Component({ selector: ‘my-app’, templateUrl: ‘./app.component.html’, styleUrls: [ ‘./app.component.css’ ] }) export class AppComponent implements OnInit {
public calendar: CalendarDay[] = [];
}
123456789 | @Component({ selector: ‘my-app’, templateUrl: ‘./app.component.html’, styleUrls: [ ‘./app.component.css’ ]})export class AppComponent implements OnInit { public calendar: CalendarDay[] = []; } |
2-й давайте посмотрим, как выглядит класс CalendarDay
JavaScript export class CalendarDay { public date: Date; public title: string; public isPastDate: boolean;
public isToday: boolean;
constructor(d: Date) { this.date = d; this.isPastDate = d.setHours(0, 0, 0, 0) < new Date().setHours(0, 0, 0, 0); this.isToday = d.setHours(0, 0, 0, 0) == new Date().setHours(0, 0, 0, 0);
}
}
12345678910111213 | export class CalendarDay { public date: Date; public title: string; public isPastDate: boolean; public isToday: boolean; constructor(d: Date) { this.date = d; this.isPastDate = d.setHours(0, 0, 0, 0) < new Date().setHours(0, 0, 0, 0); this.isToday = d.setHours(0, 0, 0, 0) == new Date().setHours(0, 0, 0, 0); } } |
Позвольте немного объяснить конструктор.
JavaScript this.isPastDate = d.setHours(0, 0, 0, 0) < new Date().setHours(0, 0, 0, 0);
this.isToday = d.setHours(0, 0, 0, 0) == new Date().setHours(0, 0, 0, 0);
Полноэкранное меню на CSS с эффектом анимации
12 | this.isPastDate = d.setHours(0, 0, 0, 0) < new Date().setHours(0, 0, 0, 0);this.isToday = d.setHours(0, 0, 0, 0) == new Date().setHours(0, 0, 0, 0); |
Я установил свойство isPastDate, чтобы календарь знал, как отображать или отключать прошлые даты, и свойство isToday, чтобы пользовательский интерфейс знал, как выводить сегодняшнюю дату.
Причина, по которой я использую .setHours (0,0,0,0), заключается в том, что я хочу быть уверен, что сравниваю начало дня, а часы не имеют значения.
3-й давайте заполним календарь необходимыми днями
У меня есть комментарии в коде, которые объясняют логику.
JavaScript ngOnInit(): void { // здесь мы инициализируем календарь this.generateCalendarDays();
}
private generateCalendarDays(): void { // мы сбрасываем календарь каждый раз
this.calendar = [];
// мы устанавливаем дату
let day: Date = new Date();
// здесь мы находим первый день, с которого начинается календарь // это должен быть последний понедельник предыдущего месяца
let startingDateOfCalendar = this.getStartDateForCalendar(day);
// dateToAdd – это an промежуточная переменная, которая увеличивается на 1 // в следующем цикле for
let dateToAdd = startingDateOfCalendar;
%MINIFYHTML7e9b31e22301e3aee061377a1819786b20% %MINIFYHTML7e9b31e22301e3aee061377a1819786b21%
// ok, так как мы имеем начальную дату, когда получаем следующие 41 день // нам нужно добавить в календарь массив // 41 значит, что нужно отображать 6 недель, и математика говорит, что // 6 недель * 7 дней = 42[HTML] for (var i = 0; i < 42; i++) { this.calendar.push(new CalendarDay(new Date(dateToAdd))); dateToAdd = new Date(dateToAdd.setDate(dateToAdd.getDate() + 1)); }
}
private getStartDateForCalendar(selectedDate: Date){ // для дня, который мы выбрали, давайте получим последний день предыдущего месяца
let lastDayOfPreviousMonth = new Date(selectedDate.setDate(0));
// начинаем с установки для календаря начальной даты, совпадающей с последним днем предыдущего месяца
let startingDateOfCalendar: Date = lastDayOfPreviousMonth;
// но так как мы фактически хотим найти последний понедельник предыдущего месяца // мы идем назад, пока не найдем последний понедельник предыдущего месяца if (startingDateOfCalendar.getDay() != 1) { do { startingDateOfCalendar = new Date(startingDateOfCalendar.setDate(startingDateOfCalendar.getDate() – 1)); } while (startingDateOfCalendar.getDay() != 1);
}
return startingDateOfCalendar;
}
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647 | ngOnInit(): void { // здесь мы инициализируем календарь this.generateCalendarDays(); } private generateCalendarDays(): void { // мы сбрасываем календарь каждый раз this.calendar = []; // мы устанавливаем дату let day: Date = new Date(); // здесь мы находим первый день, с которого начинается календарь // это должен быть последний понедельник предыдущего месяца let startingDateOfCalendar = this.getStartDateForCalendar(day); // dateToAdd – это an промежуточная переменная, которая увеличивается на 1 // в следующем цикле for let dateToAdd = startingDateOfCalendar; // ok, так как мы имеем начальную дату, когда получаем следующие 41 день // нам нужно добавить в календарь массив // 41 значит, что нужно отображать 6 недель, и математика говорит, что // 6 недель * 7 дней = 42[HTML] for (var i = 0; i < 42; i++) { this.calendar.push(new CalendarDay(new Date(dateToAdd))); dateToAdd = new Date(dateToAdd.setDate(dateToAdd.getDate() + 1)); } } private getStartDateForCalendar(selectedDate: Date){ // для дня, который мы выбрали, давайте получим последний день предыдущего месяца let lastDayOfPreviousMonth = new Date(selectedDate.setDate(0)); // начинаем с установки для календаря начальной даты, совпадающей с последним днем предыдущего месяца let startingDateOfCalendar: Date = lastDayOfPreviousMonth; // но так как мы фактически хотим найти последний понедельник предыдущего месяца // мы идем назад, пока не найдем последний понедельник предыдущего месяца if (startingDateOfCalendar.getDay() != 1) { do { startingDateOfCalendar = new Date(startingDateOfCalendar.setDate(startingDateOfCalendar.getDate() – 1)); } while (startingDateOfCalendar.getDay() != 1); } return startingDateOfCalendar; } |
В-четвертых, давайте добавим немного HTML и CSS, чтобы фактически отобразить календарь
В HTML вы увидите, что я использую пайп с именем chunk. Я немного объясню его использование и код.
Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday |
---|---|---|---|---|---|---|
{{c.date.getDate()}} {{monthNames[c.date.getMonth()]}} |
1234567891011121314151617181920 |
|
CSS .calendar-table { border-collapse: collapse; width: 100%; max-width: 100%; margin-bottom: 1rem; border: 1px solid #dee2e6; background-color: #fff;
}
.calendar-table thead th { vertical-align: bottom; border-bottom: 2px solid #dee2e6; width: 14.2%;
}
.calendar-table td, .calendar-table th { border: 1px solid #dee2e6;
}
.calendar-table td, .calendar-table th { padding: .75rem; vertical-align: top; border-top: 1px solid #dee2e6;
}
.calendar-day { height: 12vh; max-height: 12vh; cursor: pointer;
}
.calendar-items-wrapper { margin-left: -10px; margin-right: -10px; overflow-y: auto; max-height: calc(100% – 20px);
}
.calendar-day.past-date { background-color: rgb(248, 248, 248);
}
.calendar-day:hover { background-color: rgb(248, 248, 248);
}
.blue-date { color: rgb(16, 110, 190);
}
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849 | .calendar-table { border-collapse: collapse; width: 100%; max-width: 100%; margin-bottom: 1rem; border: 1px solid #dee2e6; background-color: #fff;} .calendar-table thead th { vertical-align: bottom; border-bottom: 2px solid #dee2e6; width: 14.2%;} .calendar-table td, .calendar-table th { border: 1px solid #dee2e6;} .calendar-table td, .calendar-table th { padding: .75rem; vertical-align: top; border-top: 1px solid #dee2e6;} .calendar-day { height: 12vh; max-height: 12vh; cursor: pointer;} .calendar-items-wrapper { margin-left: -10px; margin-right: -10px; overflow-y: auto; max-height: calc(100% – 20px);} .calendar-day.past-date { background-color: rgb(248, 248, 248);} .calendar-day:hover { background-color: rgb(248, 248, 248);} .blue-date { color: rgb(16, 110, 190);} |
5-й сейчас пришло время объяснить и показать код для пайпа chunk
Поскольку массив календаря содержит 42 элемента, но мы хотим показать 7 элементов в каждой строке, пайп chunk будет создавать массив из 6 массивов внутри для каждой недели.
JavaScript @Pipe({ name: ‘chunk’ })
export class ChunkPipe implements PipeTransform {
transform(calendarDaysArray: any, chunkSize: number): any { let calendarDays = [];
let weekDays = [];
calendarDaysArray.map((day,index) => { weekDays.push(day); // здесь нам нужно использовать ++ перед переменной, иначе индекс увеличится // после сравнения, а нам нужно, чтобы это происходило ДО if (++index % chunkSize === 0) { calendarDays.push(weekDays); weekDays = []; } }); return calendarDays; }
}
123456789101112131415161718192021 | @Pipe({ name: ‘chunk’})export class ChunkPipe implements PipeTransform { transform(calendarDaysArray: any, chunkSize: number): any { let calendarDays = []; let weekDays = []; calendarDaysArray.map((day,index) => { weekDays.push(day); // здесь нам нужно использовать ++ перед переменной, иначе индекс увеличится // после сравнения, а нам нужно, чтобы это происходило ДО if (++index % chunkSize === 0) { calendarDays.push(weekDays); weekDays = []; } }); return calendarDays; }} |
Этот пост был написан с любовью.
Автор: Ricky Stam
Редакция: Команда webformyself.
Источник