Angular: Как создать полноэкранный календарь, такой как в Outlook

100-5955958

От автора: некоторое время назад в проекте 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                                                                         

Monday Tuesday Wednesday Thursday Friday Saturday Sunday
        {{c.date.getDate()}} {{monthNames[c.date.getMonth()]}}      

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.

Источник