似たようなスレッドがいくつかありますが、自分のニーズに合った答えを見つけることができませんでした。したがって、angular2で直接DOMアクセスを厳密に回避する必要があるため、このベストプラクティスは何なのかと思っています。
私が達成したくないのは、現在の幅に基づいて要素のサイズを変更することです。
workitemresize.component.ts
import { Directive, ElementRef, HostListener, Renderer, Input } from '@angular/core';
@Directive({
selector: '[workItemResize]'
})
export class WorkItemResizeDirective implements ngAfterViewInit {
private el: HTMLElement;
private renderer: Renderer;
constructor(el: ElementRef, public renderer: Renderer)
{
this.el = el.nativeElement;
this.renderer = renderer;
}
@HostListener('window:resize', ['$event.target'])
onResize()
{
this.resizeWorks();
}
ngAfterViewInit() {
this.resizeWorks();
}
private resizeWorks(): void {
this.renderer.setElementStyle(this.el, 'height', this.el.width); // <-- doesn't work I kow that this.el.width doesn't exist but just for demonstration purpose
this.renderer.setElementStyle(this.el, 'height', '500'); // <-- works
}
}
projects.template.html
<div class="posts row">
<div class="work-item col-xs-12 col-sm-6 col-no-padding" workItemResize *ngFor="let post of posts">
<!-- show some fancy image -->
<div class="img" [ngStyle]="{'background-image':'url('+post.better_featured_image.source_url+')'}"></div>
</div>
</div>
nativeElement
にアクセスせずにHost要素から幅を取得する方法がわかりませんが、次のように設定できます。
@HostListener('window:resize', ['$event.target'])
onResize() {
this.resizeWorks();
}
@HostBinding('style.height.px')
elHeight:number;
private resizeWorks(): void {
this.elHeight = this.el.nativeElement.width;
}
コンポーネントテンプレート内に次のような要素を追加できる場合
<div style="width: 100%;" #div (window:resize)="elHeight = div.getBoundingClientRect()">
<!-- your template here -->
</div>
これは、DOMに直接アクセスしなくても機能します(ただし、initの後は機能しません)。
@GünterZöchbauerソリューションを試してみて、改良しました。 divの境界を取得するためにHostListenerは必要ありません。 'click'または他のイベント(event)= "function()"と同様に、この関数を起動します。誰かがこれが役立つことを願っています。
<div #div (window:resize)="onResize(div.getBoundingClientRect())">
<!-- your template here -->
</div>
onResize() {
this.resizeWorks();
}
@HostBinding('style.height.px') elHeight:number;
private resizeWorks(): void {
this.elHeight = this.el.nativeElement.width;
}
(#div)-これは、測定ターゲットを取得するために必要な変数です。要素と同じ名前である必要はなく、任意の名前を指定できます。
要素の寸法を取得するもう1つの方法は、Angular CoreのElementRefクラスを使用することですが、幅と高さのプロパティを持つ子要素を見つける必要があります。 Angular 2 Mapsでこれを使用してコンテナの幅と高さを取得しましたが、このメソッドを使用すると、これらのプロパティを持つ要素ツリー要素で見つける必要があり、ルート要素の2番目の子であることがわかりました。もっと面倒です。 ElementDimensions-これらのプロパティを含めるために作成した高さと幅のクラスです。
<div (window:resize)="onResize()">
<!-- your template here -->
</div>
private getContainerDimensions(): ElementDimensions{
var rootElement = this.elementRef.nativeElement;
var childElement = rootElement.firstElementChild;
var contentElement = childElement.firstElementChild;
return {
height:contentElement.clientHeight,
width: contentElement.clientWidth
};
}
私はこの方法でテストし、簡単に働きました!バインディングがこの仕事をしたようです。
<div #foto [style.height.px]="foto.getBoundingClientRect().width / 2">
コンポーネントに表示プロパティが定義されている場合(以下の例の「ブロック」など)、コンポーネント自体の幅を取得できます。 (Dom Shadowingを使用して)このスタイルを定義できることに注意してください。
:Host {
display:block;
}
Domシャドウ(Ionic 2-3)を使用していない場合:
my-component {
display:block;
}
コントローラーは次のとおりです(幅を監視可能として公開します)。
import {AfterViewInit, Component, ElementRef, HostListener, Input} from '@angular/core';
import {Subject} from 'rxjs/Subject';
@Component({
selector: 'my-component',
template: '{{$width|async}}',
style: 'my-component {display: block;}'
})
export class MyComponent implements AfterViewInit {
@Input() public gridWidth: number;
private $width: Subject<number> = new Subject();
constructor(private elementRef: ElementRef) {
}
public ngAfterViewInit(): void {
this.emitWidth();
}
@HostListener('window:resize', ['$event.target'])
public onResize(): void {
this.emitWidth();
}
private emitWidth(): void {
this.$width.next(this.getWidth());
}
private getWidth(): number {
return this.getNativeElement().clientWidth;
}
private getNativeElement(): HTMLElement {
return this.elementRef.nativeElement;
}
}