【发布时间】:2017-04-11 13:20:16
【问题描述】:
我正在使用 Angular 2 创建一个 3D“卡片翻转”。父“卡片翻转”组件包含一个嵌套的“卡片翻转正面”和“卡片翻转背面”组件。
<card-flip card-flip-id="demo-1" class="grid_col-6">
<card-flip-front class="card">
<div class="card__inner">
Card Front
</div>
</card-flip-front>
<card-flip-back class="card">
<div class="card__inner">
Card Back
</div>
</card-flip-back>
</card-flip>
我想创建一个卡片翻转前端组件的“克隆”,其中包含内容投影和数据绑定。 “克隆”将用于制作动画,而“原始”将保留在其隐藏的原始位置。这样,当“克隆”返回到原始位置(即使用户滚动或调整窗口大小)时,我就有了“克隆”应该动画到哪里的参考。
我面临的主要挑战是我需要将ng-content 标签中的内容也投射到“克隆”中。问题是 Angular 将使用第一个 ng-content 标签进行内容投影,而其他未标记的 ng-content 标签将为空(我知道这是预期的行为)。
有人可能会问,“为什么不直接在 DOM 中创建元素的静态副本呢?”。我想避免这种情况,以便注入数据(从而修改元素的尺寸)的嵌套组件和数据绑定将继续工作。
到目前为止,这是我的工作,它通过 ComponentFactory 创建了 CardFlipFront 组件的实例以用作“克隆”,并简单地插入“原始”CardFlipFront 的 innerHTML。
import {
Component,
ComponentFactory,
ComponentFactoryResolver,
ComponentRef,
ContentChild,
Inject,
Input,
OnInit,
ViewChild,
ViewContainerRef
} from '@angular/core';
import { CardFlipFrontComponent } from './card-flip-front.component';
import { CardFlipBackComponent } from './card-flip-back.component';
import { CardFlipService } from './card-flip.service';
@Component({
selector: 'card-flip',
templateUrl: './card-flip.component.html',
styleUrls: ['./card-flip.component.css'],
entryComponents: [
CardFlipFrontComponent
]
})
export class CardFlipComponent implements OnInit {
@Input('card-flip-id') public id: string;
@ContentChild(CardFlipFrontComponent) private front: CardFlipFrontComponent;
@ContentChild(CardFlipBackComponent) private back: CardFlipBackComponent;
@ViewChild('frontCloneContainer', { read: ViewContainerRef }) private frontCloneContainer: ViewContainerRef;
private frontComponentRef: ComponentFactory<CardFlipFrontComponent>;
private frontClone: ComponentRef<CardFlipFrontComponent>;
constructor(
@Inject(CardFlipService) private _cardFlipService: CardFlipService,
private _componentFactoryResolver: ComponentFactoryResolver
) {
this.frontComponentRef = this._componentFactoryResolver.resolveComponentFactory(CardFlipFrontComponent);
}
ngOnInit() {
this._cardFlipService.register(this.id);
}
ngAfterViewInit() {
// Create a card-flip-front component instance to serve as a "clone"
this.frontClone = this.frontCloneContainer.createComponent(this.frontComponentRef);
// Copy the innerHTML of the "original" into the "clone"
this.frontClone.instance.el.nativeElement.innerHTML = this.front.el.nativeElement.innerHTML;
}
ngOnDestroy() {
this.frontClone.destroy();
}
}
<ng-content select="card-flip-front"></ng-content>
<ng-container #frontCloneContainer></ng-container>
<ng-content select="card-flip-back"></ng-content>
import {
Component,
ElementRef,
HostBinding,
Input,
OnInit,
Renderer
} from '@angular/core';
@Component({
selector: 'card-flip-front',
templateUrl: './card-flip-front.component.html',
styleUrls: ['./card-flip-front.component.css']
})
export class CardFlipFrontComponent implements OnInit {
constructor(private _el: ElementRef, private _renderer: Renderer) { }
public get el(): ElementRef {
return this._el;
}
public get renderer(): Renderer {
return this._renderer;
}
ngOnInit() { }
}
<ng-content></ng-content>
更新:
好的,所以在阅读了一些类似的挑战和github issue here 之后,我尝试了以下操作。
<ng-template #frontTemplate>
<ng-content select="card-flip-front"></ng-content>
</ng-template>
<ng-container *ngIf="isOpen == true" #front1>
<ng-container *ngTemplateOutlet="frontTemplate"></ng-container>
</ng-container>
<ng-container *ngIf="isOpen == false" #front2>
<ng-container *ngTemplateOutlet="frontTemplate"></ng-container>
</ng-container>
<ng-content select="card-flip-back"></ng-content>
基本上,我们可以通过将ng-content 放置在模板中并使用两个带有*ngIf 语句的ng-container 标记来解决单一投影问题,该语句将仅基于类属性显示模板的一个实例isOpen.
但这并不能解决整个问题,因为在任何给定时间只会呈现一个容器。因此,我无法获取“原始”的当前位置来确定在上述返回动画期间为“克隆”设置动画的位置。
【问题讨论】:
标签: javascript angular