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

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

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

От автора: некоторое время назад в проекте Angular мне нужно было отобразить полноэкранный календарь, такой как в outlook. Поэтому, как обычный ленивый разработчик, я начал искать в Интернете пакет NPM, который мог бы сделать эту работу.

К моему удивлению, я не нашел ничего, что могло бы покрыть мои потребности на 100%, поэтому я построил свой собственный календарь! Это конечный результат:

PS: Пожалуйста, будьте снисходительны ко мне, HTML и CSS не являются моей сильной стороной.

Вот история того, как я это сделал.

1-й давайте создадим компонент Angular

Это наша отправная точка, компонент Angular и массив, который будет содержать дни, для которых будет отображаться календарь.

@Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit { public calendar: CalendarDay[] = []; }

2-й давайте посмотрим, как выглядит класс CalendarDay

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); } }

Позвольте немного объяснить конструктор.

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-й давайте заполним календарь необходимыми днями

У меня есть комментарии в коде, которые объясняют логику.

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. Я немного объясню его использование и код.

<table class='calendar-table' *ngIf="calendar"> <thead> <tr> <th>Monday</th> <th>Tuesday</th> <th>Wednesday</th> <th>Thursday</th> <th>Friday</th> <th>Saturday</th> <th>Sunday</th> </tr> </thead> <tbody> <tr *ngFor="let row of calendar | chunk: 7; let i = index"> <td class="calendar-day" [ngClass]="{'past-date': c.isPastDate, 'today': c.isToday}" *ngFor="let c of row; let j = index"> <div class="calendar-day-header" [ngClass]="{'blue-date': c.isToday}"><strong>{{c.date.getDate()}}</strong> <strong *ngIf="c.isToday || (i==0 && j==0) || (c.date.getDate() == 1)"> {{monthNames[c.date.getMonth()]}}</strong></div> </td> </tr> </tbody>
</table>

.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 массивов внутри для каждой недели.

@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

Источник: https://dev.to

Редакция: Команда webformyself.