Angular中的绝对定位div

Androidian

我正在为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)
            };
        });

使用该代码,结果如下: 在此处输入图片说明

如您所见,事件div的位置不正确。我认为这是由于网格单元格边框所致,所以我已应用了该修复程序:

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

每个边框的宽度均为1px,我只考虑实心边框,而不考虑虚线边框(这是的动机/ 2

这几乎解决了问题。仍然存在偏差。而且,这不是一个优雅的解决方案,但我不知道要使其更干净。

如何正确定位这些div?

非常感谢你!

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

mixinsscss文件中创建了以下内容

@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}`;
}

结果如下:

在此处输入图片说明

在图形上,它像一个超级按钮一样工作,但是我需要使线段的高度(58px)与用于生成定位类的百分比增量(现在是)对齐1.47%

有没有办法从Angular代码中使这些变量(段高度和百分比高度以及顶部位置的增量)成为可能,使段高度可由用户配置,并使这些增量适应自身?

非常感谢你!

编辑2:另一个问题

Hi again! I've encountered another problem. The component hour range it is not fixed but it is configurable from outside. In the example in the question is 6AM - 22PM. For that range the percentage of 1.47 is fine but if I change the range (eg. 0AM - 22AM) the calendar height is higher and the percentage is not ok anymore.

I think I need to calculate those positioning values from Typescript. But I can't figure out how to do that.

To try something I'm trying this:

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

Then I've added [style.top.%]="event.top" to the event div. This is the result (ignore height for now, I've not managed them yet):

在此处输入图片说明

As you can see the percentage is not accurate and those events which are in the middle of the day (or towards the end of the day) are not positioned correctly.

How could I solve this problem? Thank you very much, again!

inorganik

It seems like a brittle solution to calculate pixel distances in code. I would use CSS classes. You can have an SCSS mixin generate all the possible classes for you for days, times and segment lengths. Make 3 methods that return css class strings, one for day, one for time, and one for segment length which you can apply with [ngClass]. Then a method which calls each one, something like below. This assumes you have an array of segments which store date/time/length info on them:

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

So your markup might end up looking like this:

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

Compiled:

<segment class="day0 time1430 length130"></segment>
  • day0 - you could have 0-X for however many days you display. This class is just responsible for distance from the left. Use percentages if you can so that the layout can be flexible.
  • time1430 in this case 2:30pm - This class is just responsible for distance from the top
  • length130在这种情况下,一个半小时。理想情况下,将最小时间增量(15m?)设置为百分比高度,然后让mixin将每个可能的长度乘以增量。

另外,要确保您不必考虑边界问题,请将box-sizing: border-boxCSS规则应用于几乎所有内容。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章