我正在制作一个 Angular 应用程序 + Tailwind,它是一个大型水平页面,允许用户使用
scroll-snap-type
从左向右滚动。当我尝试清理代码并创建可重用组件时,呈现的 html 与我将所有 HTML 放在一个组件中时不同。
我创建了一个ScrollContainerComponent:
import { ChangeDetectionStrategy, Component, ElementRef, ViewChild } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-scroll-container',
standalone: true,
template: `
<div
class="flex snap-x snap-proximity h-screen w-full mx:auto overflow-x-scroll overflow-y-hidden "
#scrollContainer
>
<ng-content></ng-content>
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ScrollContainerComponent {
@ViewChild('scrollContainer')
scrollContainer!: ElementRef;
ngAfterViewInit() {
this.scrollContainer.nativeElement.addEventListener('keydown', this.handleKeydown.bind(this));
}
handleKeydown(event: KeyboardEvent) {
switch (event.key) {
case 'ArrowLeft':
this.scrollLeft();
break;
case 'ArrowRight':
this.scrollRight();
break;
}
}
scrollLeft() {
this.scrollContainer.nativeElement.scrollLeft -= 100;
}
scrollRight() {
this.scrollContainer.nativeElement.scrollLeft += 100;
}
}
还有一个孩子:
import { ChangeDetectionStrategy, Component } from '@angular/core';
@Component({
selector: 'app-scroll-child',
template: `<div class="snap-start shrink-0 grid w-full h-screen place-items-center text-8xl">
<ng-content></ng-content>
</div>`,
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
})
export class ScrollChildComponent {}
但是,只有当我像这样使用它时它才有效:
<app-scroll-container>
<div class="snap-start shrink-0 bg-amber-200 grid w-full h-screen place-items-center text-8xl">1</div>
<div class="snap-start shrink-0 bg-blue-200 grid w-screen h-screen place-items-center text-8xl">2</div>
<div class="snap-start shrink-0 bg-orange-200 grid w-screen h-screen place-items-center text-8xl">3</div>
<div class="snap-start shrink-0 bg-green-200 grid w-screen h-screen place-items-center text-8xl">4</div>
</app-scroll-container>
而不是使用
<app-scroll-child>1</app-scroll-child>
。
请帮我删除包装元素角度添加到
app-scroll-child
这可能有点 hacky,但您可以让容器组件从每个子组件中提取内容,手动将该内容附加到自身,然后从其视图中删除子组件。
为此,子组件需要有对其视图内容的公共引用,以便容器组件可以访问它,如下所示:
@Component({
selector: 'app-scroll-child',
template: `<div #targetEl <------------------------ Add this template variable
class="snap-start shrink-0 grid w-full
h-screen place-items-center text-8xl">
<ng-content></ng-content>
</div>`,
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
})
export class ScrollChildComponent {
@ViewChild('targetEl') targetEl: ElementRef; // <-- and this reference to it
}
然后,在容器组件中,您需要添加一个 ContentChildren 引用,以允许容器迭代子级、提取其内容并将其内容直接附加到容器内,如下所示:
export class ScrollContainerComponent {
@ViewChild('scrollContainer')
scrollContainer: ElementRef;
@ContentChildren (ScrollChildComponent)
scrollChildComponents: QueryList<ScrollChildComponent> // <-- Add this
ngAfterViewInit() {
this.scrollChildComponents.forEach((child: ScrollChildComponent) => { // <-- and this
this.scrollContainer.nativeElement.appendChild(child.targetEl.nativeElement)
})
}
}
将子内容直接附加到容器中后,您只需删除子组件引用/包装器即可。
为此,您可以将
*ngIf
附加到容器内的 ng-content
,并在内容附加完成后,将 *ngIf
引用设置为 false
,这将从容器中删除 <app-scroll-child>
元素。容器。
因此您的容器组件更改将如下所示:
@Component({
selector: 'app-scroll-container',
standalone: true,
imports: [
CommonModule
],
template: `
<div
class="flex snap-x snap-proximity h-screen w-full mx:auto overflow-x-scroll overflow-y-hidden "
#scrollContainer
>
<ng-content *ngIf="showContentChildren"></ng-content> <----- Add *ngIf here
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ScrollContainerComponent {
@ViewChild('scrollContainer') scrollContainer: ElementRef;
@ContentChildren (ScrollChildComponent) scrollChildComponents: QueryList<ScrollChildComponent>
protected showContentChildren = true
constructor(
private cd: ChangeDetectorRef
) {}
ngAfterViewInit() {
this.scrollChildComponents.forEach((child: ScrollChildComponent) => {
this.scrollContainer.nativeElement.appendChild(child.targetEl.nativeElement)
})
setTimeout(() => {
this.showContentChildren = false // <------------ hide child components here
this.cd.markForCheck()
})
}
}
这里有一个 StackBlitz 展示了这种方法。