Как получить ширину элемента (DOM) в Angular2

есть похожие похожие темы, но я не нашел подходящего ответа для моих нужд. Так что прямой доступ DOM следует строго избегать в angular2 Мне просто интересно, что лучше всего подходит для этого.

То, чего я не достиг, - это изменение размера элемента на основе текущей ширины.

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>

по теме: https://github.com/angular/angular/issues/6515

Ответ 1

Я не знаю способа получить ширину от элемента хоста без доступа к nativeElement, но настройка может быть выполнена следующим образом:

@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).

Ответ 2

Я опробовал решение GünterZöchbauer и усовершенствовал его. Вам не нужен HostListener, чтобы получить границы div. Подобно 'click' или другому событию (событию) = "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) - это переменная, необходимая для получения цели измерения. Это не должно быть то же имя, что и элемент, это может быть любое имя.

Еще один способ получить размеры элементов - использовать класс ElementRef из Angular Core, но тогда вам нужно найти этот дочерний элемент, который имеет свойства ширины и высоты. Я использовал это в Angular 2 Maps, чтобы получить ширину и высоту контейнера, но я узнал, что, используя этот метод, мне пришлось найти элемент элемента дерева, который имел эти свойства, и он был вторым потомком корневого элемента. Это более грязно. 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
    };
}

Ответ 3

Вы можете получить ширину самого компонента, если у этого есть определенное свойство отображения (например, "блок" в приведенном ниже примере). Обратите внимание, что вы должны быть в состоянии определить этот стиль (используя dom shadowing):

:host {
    display:block;
}

Если вы не используете dom shadowing (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;
    }
}