Angular中的绝对定位div

问题描述 投票:1回答:1

我正在为Angular开发一个日历组件,我需要在网格中放置一些div元素(表示事件)。

this.days.forEach((day: SchedulerViewDay, dayIndex: number) => {
        day.events = this.getEventsInPeriod({...}).map((event: CalendarSchedulerEvent) => {
            const segmentDuration: number = 60.0 / this.hourSegments;
            const dayStartDate: Date =
                setSeconds(setMinutes(setHours(
                setDate(setMonth(setYear(new Date(), day.date.getFullYear()), day.date.getMonth()), day.date.getDate()), this.dayStartHour), this.dayStartMinute), 0);
            const segmentsNumber: number = (differenceInMinutes(event.start, dayStartDate) / segmentDuration);

            return <CalendarSchedulerEvent>{
                ...
                height: this.hourSegmentHeight * (differenceInMinutes(event.end, event.start) / segmentDuration),
                top: (this.hourSegmentHeight * segmentsNumber)
            };
        });

使用该代码,结果就是:enter image description here

如您所见,事件div未正确定位。我认为这是由于网格单元边框所以我已应用该修复:

top: (this.hourSegmentHeight * segmentsNumber) + (segmentsNumber / 2) // 1px for each separator line

每个边框宽度为1px,我认为只有实线边框而不是虚线边框(这是/ 2的动机。

这几乎解决了这个问题。还有一个错位。此外,这不是一个优雅的解决方案,但我无法弄清楚它是否更干净。

我怎样才能正确定位这些div?

非常感谢你!

编辑:inorganik解决方案的实施(第一个答案)

我在mixins文件中创建了以下scss

@mixin day-x($attr, $attr-count: 7, $attr-steps: 1, $unit: '%') {
    $attr-list: null;

    @for $i from 1 through $attr-count {
        $attr-value: $attr-steps * $i;

        &.day#{$i} {
            #{$attr}: #{$attr-value}#{$unit};
        }

        $attr-list: append($attr-list, unquote(".#{$attr}-#{$attr-value}"), comma);
    }

    #{$attr-list} {
        //append style to all classes
    }
}

@mixin time-x($attr, $start-hour: 0, $end-hour: 23, $attr-steps: 2, $minutes-steps: 15, $unit: '%') {
    $attr-list: null;
    $hours: $start-hour;
    $minutes: 0;
    $attr-count: ((($end-hour + 1) - $start-hour) * 60) / $minutes-steps;

    @for $i from 0 through $attr-count {
        $attr-value: $attr-steps * $i;

        @if($i > 0) {
            $minutes: $minutes + $minutes-steps;
            @if($minutes == 60) {
                $minutes: 0;
                $hours: $hours + 1;
            }
        }

        $hoursString: '#{$hours}';
        @if($hours < 10) {
            $hoursString: '0#{$hours}';
        }

        $minutesString: '#{$minutes}';
        @if($minutes < 10) {
            $minutesString: '0#{$minutes}';
        }

        &.time#{$hoursString}#{$minutesString} {
            #{$attr}: #{$attr-value}#{$unit};
        }

        $attr-list: append($attr-list, unquote(".#{$attr}-#{$attr-value}"), comma);
    }

    #{$attr-list} {
        //append style to all classes
    }
}

@mixin length-x($attr, $attr-steps: 2, $minutes-steps: 15, $unit: '%') {
    $attr-list: null;
    $attr-count: 24 * 60 / $minutes-steps;

    @for $i from 0 through $attr-count {
        $attr-name: $minutes-steps * $i;
        $attr-value: $attr-steps * $i;

        &.length#{$attr-name} {
            #{$attr}: #{$attr-value}#{$unit};
        }

        $attr-list: append($attr-list, unquote(".#{$attr}-#{$attr-value}"), comma);
    }

    #{$attr-list} {
        //append style to all classes
    }
}

@include day-x('left', 7, 5);
@include time-x('top', 6, 22, 1.47);
@include length-x('height', 1.47);

然后我用[ngClass]属性应用这些样式,调用以下方法(我现在不需要getDay):

getPositioningClasses(event: CalendarSchedulerEvent): string {
    const classes: string[] = [
        this.getDayClass(event.start),
        this.getTimeClass(event.start),
        this.getLengthClass(differenceInMinutes(event.end, event.start))
    ];
    return classes.join(' ');
}

private getDayClass(date: Date): string {
    return '';
}
private getTimeClass(date: Date): string {
    let hours: string = date.getHours() < 10 ? `0${date.getHours()}` : `${date.getHours()}`;
    let minutes: string = date.getMinutes() < 10 ? `0${date.getMinutes()}` : `${date.getMinutes()}`;
    return `time${hours}${minutes}`;
}
private getLengthClass(durationInMinutes: number): string {
    return `length${durationInMinutes}`;
}

这是结果:

enter image description here

从图形上看,它就像一个魅力,但我需要保持段高度(58px)与用于生成定位类的百分比增量(现在是1.47%)对齐。

有没有办法从Angular代码中创建这些变量(段高度和百分比高度以及顶部位置增量),使得用户可以配置段高度并让这些增量自行调整?

非常感谢你!

编辑2:另一个问题

你好,我们又见面了!我遇到了另一个问题。组件小时范围不是固定的,但可以从外部配置。在问题的例子是早上6点 - 晚上22点。对于该范围,1.47的百分比是好的但是如果我改变范围(例如,0AM-22AM),则日历高度更高并且百分比不再是正常的。

我想我需要从Typescript计算这些定位值。但我无法弄清楚如何做到这一点。

尝试一下我正在尝试这个:

ngAfterViewInit(): void {
    this.calendarContainerHeight = this.calendarContainer.nativeElement.clientHeight;
    const segmentPercentage: number = 100.0 * this.hourSegmentHeight / this.calendarContainerHeight;
    console.log("calendarContainerHeight: ", this.calendarContainerHeight);
    console.log("segmentPercentage: ", segmentPercentage);

    setTimeout(() => {
        this.view.days.forEach(d => {
            d.events.forEach((event: CalendarSchedulerEvent) => {
                let hours: number = event.start.getHours();
                if (this.dayStartHour > 0) { hours = hours - this.dayStartHour; }

                const numberOfSegments: number = hours * this.hourSegments;
                event.top = numberOfSegments * segmentPercentage;
            });
        });
    });
}

然后我将[style.top.%]="event.top"添加到事件div中。这是结果(暂时忽略高度,我还没有管理它们):

enter image description here

正如您所看到的,百分比不准确,并且那些在一天中间(或在一天结束时)的事件未正确定位。

我怎么能解决这个问题?再一次非常感谢你!

html css angular css-position
1个回答
0
投票

在代码中计算像素距离似乎是一个脆弱的解决方案。我会使用CSS类。您可以让SCSS mixin为您生成所有可能的类,包括日期,时间和段长度。制作3个返回css类字符串的方法,一个用于日期,一个用于时间,一个用于段长度,您可以使用[ngClass]。然后是一个调用每个方法的方法,如下所示。这假设您有一系列段来存储日期/时间/长度信息:

getPositioningClasses(segment: any): string {
  const classes = [this.getDayClass(segment.dayStartDate), this.getTimeClass(segment.dayStartDate), this.getLengthClass(segment.timeLength)];
  return classes.join(' ');
}

所以你的标记可能最终看起来像这样:

<segment [ngClass]="getPositioningClasses(segment)"></segment>

编译:

<segment class="day0 time1430 length130"></segment>
  • day0 - 无论你显示多少天,都可以拥有0-X。这个班负责离开左边的距离。如果可以,请使用百分比,以便布局灵活。
  • time1430在这种情况下下午2:30 - 这个班级负责距离顶部的距离
  • 在这种情况下,length130一个半小时。理想情况下,将最小时间增量(15m?)设置为百分比高度,然后让mixin乘以每个可能长度的增量。

另外,为了确保您不必考虑边界,请将box-sizing: border-box css规则放在几乎所有内容上。

© www.soinside.com 2019 - 2024. All rights reserved.