如何在Angular2中获取(DOM)元素的宽度

Posted

技术标签:

【中文标题】如何在Angular2中获取(DOM)元素的宽度【英文标题】:How to get width of (DOM) Element in Angular2 【发布时间】:2016-12-29 06:48:03 【问题描述】:

有一些类似的主题,但我找不到合适的答案 满足我的需要。所以应该严格避免直接 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

【问题讨论】:

根据电流调整大小,听起来像是一个无限循环。 不只是在初始化视图和 window.resize 之后 - 应该没问题 【参考方案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 之后)。

【讨论】:

@HostBinding 和 Renderer 方法之间有什么显着区别吗?我觉得两个版本都不错?哦,this.el.nativeElement.width 总是为空......所以我也在努力解决这个问题。怎么样:this.renderer.setElementStyle(this.el, 'height', this.el.clientWidth+'px');它有效,但对我来说看起来很奇怪...... 渲染器方法也很好。我发现HostBinding 方法更易于阅读。您的问题有this.el.width 而不是this.el.nativeElement.width。我假设在组件完全呈现之前调用resizeWorks,否则尝试getBoundingClientRect().width this.el 对 el.nativeElement 的引用(参见构造函数)。好的,我坚持使用 getBoundingClientRect().width。谢谢!最后的代码行:this.renderer.setElementStyle(this.el, 'height', this.el.getBoundingClientRect().width+"px"); 对。对不起,错过了那个。那么getBoundingClientRect() 工作了吗?【参考方案2】:

我试用了@GünterZöchbauer 解决方案并对其进行了改进。您不需要 HostListener 来获取 div 的边界。与 '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) - 这是获取测量目标所需的变量。它不必与元素同名,可以是任何名称。

另一种获取元素尺寸的方法是使用 Angular Core 中的 ElementRef 类,但是您必须找到具有宽度和高度属性的子元素。我在 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 阴影):

: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;
    

【讨论】:

【参考方案4】:

我以这种方式进行了测试并且很简单!似乎绑定完成了这项工作。

<div #foto [style.height.px]="foto.getBoundingClientRect().width / 2">

【讨论】:

这很聪明。 这行得通,但 Angular 的变更检测将使浏览器在每次检测到变更时运行getBoundingClientRect 方法。除非您特别希望以这种方式更新该 div 的样式,否则您应该将该宽度存储在 .ts 文件中,并仅在需要时更新它。

以上是关于如何在Angular2中获取(DOM)元素的宽度的主要内容,如果未能解决你的问题,请参考以下文章

如何在angular2和ionic2中同时保留组件的DOM元素和模板字符串

如何获取数组中每个dom元素的宽度?

vue获取dom元素的宽高

Angular2 - 将 div 添加到 DOM

Js如何获取某Dom元素的宽高

viewChild如何获取angular2中用js添加的元素?