Angular 中的绝对定位 div
Absolute positioning divs in Angular
我正在为 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 解决方案的实施(第一个答案)
我在 scss
文件中创建了以下 mixins
:
@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:另一个问题
大家好!我遇到了另一个问题。
组件小时范围不是固定的,但可以从外部配置。
在问题的例子中是早上 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 中。这是结果(暂时忽略高度,我还没有管理它们):
如您所见,百分比不准确,并且那些在一天中间(或接近一天结束)的事件没有正确定位。
我该如何解决这个问题?
再次感谢!
在代码中计算像素距离似乎是一个脆弱的解决方案。我会使用 CSS classes。你可以让 SCSS mixin 为你生成天数、时间和段长度的所有可能的 classes。创建 return css class 字符串的 3 种方法,一种用于日期,一种用于时间,一种用于段长度,您可以使用 [ngClass]
应用。然后是调用每个方法的方法,如下所示。这假设你有一个存储 date/time/length 信息的段数组:
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。这个class只是负责离左边的距离。尽可能使用百分比,这样布局可以灵活。
time1430
在这种情况下 2:30pm - 这个 class 只负责与顶部的距离
length130
在这个例子中是一个半小时。理想情况下将最小的时间增量(15m?)设置为百分比高度,然后让 mixin 乘以每个可能长度的增量。
另外,为了确保您不必考虑边框,请将 box-sizing: border-box
css 规则应用于几乎所有内容。
我正在为 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 解决方案的实施(第一个答案)
我在 scss
文件中创建了以下 mixins
:
@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:另一个问题
大家好!我遇到了另一个问题。 组件小时范围不是固定的,但可以从外部配置。 在问题的例子中是早上 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 中。这是结果(暂时忽略高度,我还没有管理它们):
如您所见,百分比不准确,并且那些在一天中间(或接近一天结束)的事件没有正确定位。
我该如何解决这个问题? 再次感谢!
在代码中计算像素距离似乎是一个脆弱的解决方案。我会使用 CSS classes。你可以让 SCSS mixin 为你生成天数、时间和段长度的所有可能的 classes。创建 return css class 字符串的 3 种方法,一种用于日期,一种用于时间,一种用于段长度,您可以使用 [ngClass]
应用。然后是调用每个方法的方法,如下所示。这假设你有一个存储 date/time/length 信息的段数组:
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。这个class只是负责离左边的距离。尽可能使用百分比,这样布局可以灵活。time1430
在这种情况下 2:30pm - 这个 class 只负责与顶部的距离length130
在这个例子中是一个半小时。理想情况下将最小的时间增量(15m?)设置为百分比高度,然后让 mixin 乘以每个可能长度的增量。
另外,为了确保您不必考虑边框,请将 box-sizing: border-box
css 规则应用于几乎所有内容。