You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Angular Material日期选择器中实现整周选择、高亮及防重叠?

Angular Material日期选择器整周选择实现方案

1. 自定义DateAdapter适配周选择逻辑

首先扩展Angular Material的NativeDateAdapter,让日期选择器默认以周一作为周起始,同时将选中日期自动转换为当周周一:

import { NativeDateAdapter } from '@angular/material/core';
import { Injectable } from '@angular/core';

@Injectable()
export class WeekDateAdapter extends NativeDateAdapter {
  // 设置周起始为周一
  override getFirstDayOfWeek(): number {
    return 1;
  }

  // 获取当前日期所属周的周一
  getWeekStartDate(date: Date): Date {
    const dayOfWeek = date.getDay();
    const diff = date.getDate() - dayOfWeek + (dayOfWeek === 0 ? -6 : 1);
    return new Date(date.setDate(diff));
  }

  // 格式化显示为周范围(可选)
  override format(date: Date, displayFormat: Object): string {
    const weekStart = this.getWeekStartDate(date);
    const weekEnd = new Date(weekStart);
    weekEnd.setDate(weekStart.getDate() + 6);
    return `${this.formatDate(weekStart)} - ${this.formatDate(weekEnd)}`;
  }

  private formatDate(date: Date): string {
    return `${date.getFullYear()}-${(date.getMonth()+1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`;
  }
}

在模块中注册适配器:

import { NgModule } from '@angular/core';
import { DateAdapter } from '@angular/material/core';
import { WeekDateAdapter } from './week-date-adapter';

@NgModule({
  providers: [
    { provide: DateAdapter, useClass: WeekDateAdapter }
  ]
})
export class AppModule { }

2. 自定义日期面板实现整周高亮

通过自定义mat-datepicker的面板模板,结合CSS实现整周高亮效果:

组件HTML模板

<mat-form-field>
  <input matInput [matDatepicker]="picker" [(ngModel)]="selectedWeekStart">
  <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
  <mat-datepicker #picker panelClass="week-highlight-datepicker">
    <mat-calendar 
      [selected]="selectedWeekStart"
      (selectedChange)="onDateSelected($event)"
      (mouseenter)="onDateHover($event)"
      [dateClass]="getDateClass.bind(this)">
    </mat-calendar>
  </mat-datepicker>
</mat-form-field>

组件TS逻辑

import { Component } from '@angular/core';
import { WeekDateAdapter } from './week-date-adapter';

@Component({
  selector: 'app-week-date-picker',
  templateUrl: './week-date-picker.component.html',
  styleUrls: ['./week-date-picker.component.css']
})
export class WeekDatePickerComponent {
  selectedWeekStart: Date | null = null;
  hoveredWeekDates: Date[] = [];
  selectedWeeks: { start: Date, end: Date }[] = [];

  constructor(private dateAdapter: WeekDateAdapter) {}

  // 处理日期点击,转换为周起始并检查重叠
  onDateSelected(date: Date | null): void {
    if (!date) return;
    const weekStart = this.dateAdapter.getWeekStartDate(date);
    const weekEnd = new Date(weekStart);
    weekEnd.setDate(weekStart.getDate() + 6);

    // 判断是否与已选周重叠
    const isOverlapping = this.selectedWeeks.some(week => {
      return !(weekEnd < week.start || weekStart > week.end);
    });

    if (isOverlapping) {
      alert('该周已被选择或与已选周重叠');
      return;
    }

    this.selectedWeekStart = weekStart;
    this.selectedWeeks.push({ start: weekStart, end: weekEnd });
  }

  // 处理鼠标hover,获取当前日期所属周的所有日期
  onDateHover(date: Date): void {
    const weekStart = this.dateAdapter.getWeekStartDate(date);
    this.hoveredWeekDates = [];
    for (let i = 0; i < 7; i++) {
      const day = new Date(weekStart);
      day.setDate(weekStart.getDate() + i);
      this.hoveredWeekDates.push(day);
    }
  }

  // 给周内日期添加高亮类
  getDateClass(date: Date): string {
    const isHoveredWeek = this.hoveredWeekDates.some(d => this.isSameDay(d, date));
    const isSelectedWeek = this.selectedWeeks.some(week => {
      return date >= week.start && date <= week.end;
    });

    if (isSelectedWeek) return 'selected-week';
    if (isHoveredWeek) return 'hovered-week';
    return '';
  }

  // 判断两个日期是否为同一天
  private isSameDay(date1: Date, date2: Date): boolean {
    return date1.getFullYear() === date2.getFullYear() &&
           date1.getMonth() === date2.getMonth() &&
           date1.getDate() === date2.getDate();
  }
}

高亮样式(CSS)

.week-highlight-datepicker .hovered-week {
  background-color: rgba(0, 123, 255, 0.1);
}

.week-highlight-datepicker .selected-week {
  background-color: rgba(0, 123, 255, 0.2);
  font-weight: bold;
}

.week-highlight-datepicker .selected-week.mat-calendar-body-selected {
  background-color: #007bff;
  color: white;
}

3. 关键逻辑说明

  • 周起始转换:通过getWeekStartDate方法,将任意选中日期转为当周周一,确保选中值统一为周起始。
  • 整周高亮:监听鼠标hover和点击事件,计算对应周的所有日期,通过dateClass动态添加CSS类实现高亮。
  • 重叠限制:维护已选周的日期范围列表,每次选择新周时,通过日期范围对比判断是否重叠,若重叠则阻止选择。

内容的提问来源于stack exchange,提问作者adnan ali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 17:05:25