2016-08-22 1571 views
12

有一些类似的线程,但我找不到合适的答案 满足我的需求。因此,应该严格避免直接DOM访问 in angular2我只是想知道这是什么最佳实践。如何在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> 

相关: https://github.com/angular/angular/issues/6515

+0

根据当前的声音调整大小,使声音像无限循环一样。 –

+0

不只是在初始化视图和window.resize之后 - 应该没事 – kkern

回答

10

我不知道一种方式来获得的宽度从主机元素不访问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。

+0

@HostBinding和Renderer方法之间有什么明显的区别吗?我认为这两个版本都很好? 哦,this.el.nativeElement.width始终为空......所以我也在为此苦苦挣扎。那么:this.renderer.setElementStyle(this.el,'height',this.el.clientWidth +'px');它的作品,但看起来很奇怪... – kkern

+0

渲染器的方法也很好。我发现'HostBinding'方法更易于阅读。你的问题有'this.el.width'而不是'this.el.nativeElement.width'。我假设'resizeWorks'在组件完全呈现之前被调用,否则就尝试'getBoundingClientRect()。width'。 –

+1

this.el引用el.nativeElement(请参阅构造函数)。好吧,我坚持getBoundingClientRect()。宽度。谢谢! 最终代码行: this.renderer.setElementStyle(this.el,'height',this.el.getBoundingClientRect()。width +“px”); – kkern

8

我尝试了@GünterZöchbauer解决方案并对其进行了改进。您不需要HostListener来获取div的界限。与“点击”或其他事件(事件)=“功能()”一样,它将触发此功能。我希望有人会觉得这有帮助。

<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 
    }; 
} 
+0

也是一个不错的解决方案! – kkern

0

如果组件本身具有定义的显示属性(例如下面示例中的“块”),则可以获取组件的宽度。需要注意的是,你应该能够(使用DOM阴影)来定义这种风格:

:host { 
    display:block; 
} 

如果你不使用DOM阴影(离子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; 
    } 
}