Обнаружение изменений размера окна в реальном времени в Angular 4


119

Я пытался создать гибкую навигационную панель и не хочу использовать медиа-запросы, поэтому я намерен использовать *ngIFразмер окна в качестве критерия. Но я столкнулся с проблемой, так как я не могу найти какой-либо метод или документацию по определению размера окна Angular 4. Я также пробовал использовать метод JavaScript, но он не поддерживается.

Я также пробовал следующее :

constructor(platform: Platform) {
    platform.ready().then((readySource) => {
        console.log('Width: ' + platform.width());
        console.log('Height: ' + platform.height());
    });
}

... который использовался в ionic.

И screen.availHeight, но все равно безуспешно.


1
О чем platform? Это про ионный?
Günter Zöchbauer

@ Günter Zöchbauer Платформа угловатая, просто хотел упомянуть коды, которые я пробовал.
Ronit Oommen

1
Platformэто ионный сервис. Итак, я предполагаю, что это ионный проект?
robbannn


@BlackBeard Я не думаю, что это дубликат из-за того, насколько сильно отличаются Angular 2 и 4.
Tehlivi

Ответы:


262

Чтобы получить его при инициализации

public innerWidth: any;
ngOnInit() {
    this.innerWidth = window.innerWidth;
}

Если вы хотите обновлять его при изменении размера:

@HostListener('window:resize', ['$event'])
onResize(event) {
  this.innerWidth = window.innerWidth;
}

2
this.innerWidth = event.target.innerWidth; ... возможно, более эффективен, дает тот же результат
danday74

2
Также рекомендуется использовать это в конструкторе, если вы используете lodash ... this.onResize = debounce (this.onResize, 150, {lead: false, trailing: true}) ... чтобы предотвратить слишком частый вызов метода onResize .. . вам нужно будет ... импортировать {debounce} из 'lodash'
danday74

Я думаю, что предпочел использовать ngAfterViewInitметод крюка жизни вместо ngOnInit метода крюка жизни
Ахмед Хамди

41

Если вы хотите реагировать на определенные точки останова (например, сделать что-нибудь, если ширина меньше 768 пикселей), вы также можете использовать BreakpointObserver:

import {BreakpointObserver, Breakpoints} from '@angular/cdk/layout';

{ ... }

const isSmallScreen = breakpointObserver.isMatched('(max-width: 599px)');

или даже послушайте изменения в этой точке останова:

breakpointObserver.observe([
  '(max-width: 768px)'
    ]).subscribe(result => {
      if (result.matches) {
        doSomething();
      } else {
        // if necessary:
        doSomethingElse();
      }
    });

если вы хотите действовать, только если наблюдатель соответствует критериям, которые вы должны добавить внутри, подпишитесь на это, if (result.matches)иначе он вызовет, даже если это не так
karoluS

1
@karoluS: Да, конечно. Я отредактировал свой ответ, чтобы прояснить это. Спасибо.
Джереми Бэнкс,

Кажется, что это cdk одноранговая зависимость от конкретной версии angular. Вроде 7 на последнюю. В любом случае я могу использовать это для более старой версии (angular 4, как в вопросе)?
LeOn - Хан Ли

@Leon li: Я действительно использую angular 7, верно. Однако: насколько я знаю, вы также можете использовать cdk в angular 4. Согласно этому сообщению в блоге вам понадобится cdk 2.x. Насколько мне известно, его нужно установить вручную и с указанной версией: npm @ angular / cdk @ 4
Джереми Бенкс

@JeremyBenks Y, мы специально используем ng 4.2.6. Не могу найти версию cdk 2.x на этом, только 4.1.x и 4.3.x. В любом случае, спасибо!
LeOn - Хан Ли

9

Если вы хотите, чтобы ваши компоненты оставались легко тестируемыми, вам следует обернуть глобальный объект окна в Angular Service:

import { Injectable } from '@angular/core';

@Injectable()
export class WindowService {

  get windowRef() {
    return window;
  }

}

Затем вы можете ввести его, как любой другой сервис:

constructor(
    private windowService: WindowService
) { }

И потреблять ...

  ngOnInit() {
      const width= this.windowService.windowRef.innerWidth;
  }

2
Я не вижу смысла делать услугу именно так, как она уже есть. window.innerWidth.
Родриго

1
Во-первых, DI - это способ Angular, который делает зависимости компонента / директивы более понятными. Но главное, о чем здесь говорится, - это упростить тестирование кода, использующего службу. Используя этот подход, WindowService можно смоделировать в любом тесте, написанном для компонентов, которые используют эту службу.
Kildareflare

9

В документации для Platform width()и height()указано, что эти методы используют window.innerWidthи window.innerHeightсоответственно. Но использование этих методов предпочтительнее, поскольку измерения представляют собой кэшированные значения, что снижает вероятность многократного и дорогостоящего чтения DOM.

import { Platform } from 'ionic-angular';

...
private width:number;
private height:number;

constructor(private platform: Platform){
    platform.ready().then(() => {
        this.width = platform.width();
        this.height = platform.height();
    });
}

Как получать widthот windowсвязаны DOM? По логике, это не должно зависеть от того, как выглядит дерево доменов.
Шахрияр Салджуги,

7

Это пример сервиса, которым я пользуюсь.

Вы можете получить ширину экрана, подписавшись на screenWidth$или черезscreenWidth$.value .

То же самое для mediaBreakpoint$(или mediaBreakpoint$.value)

import {
  Injectable,
  OnDestroy,
} from '@angular/core';
import {
  Subject,
  BehaviorSubject,
  fromEvent,
} from 'rxjs';
import {
  takeUntil,
  debounceTime,
} from 'rxjs/operators';

@Injectable()
export class ResponsiveService implements OnDestroy {
  private _unsubscriber$: Subject<any> = new Subject();
  public screenWidth$: BehaviorSubject<number> = new BehaviorSubject(null);
  public mediaBreakpoint$: BehaviorSubject<string> = new BehaviorSubject(null);

  constructor() {}

  init() {
    this._setScreenWidth(window.innerWidth);
    this._setMediaBreakpoint(window.innerWidth);
    fromEvent(window, 'resize')
      .pipe(
        debounceTime(1000),
        takeUntil(this._unsubscriber$)
      ).subscribe((evt: any) => {
        this._setScreenWidth(evt.target.innerWidth);
        this._setMediaBreakpoint(evt.target.innerWidth);
      });
  }

  ngOnDestroy() {
    this._unsubscriber$.next();
    this._unsubscriber$.complete();
  }

  private _setScreenWidth(width: number): void {
    this.screenWidth$.next(width);
  }

  private _setMediaBreakpoint(width: number): void {
    if (width < 576) {
      this.mediaBreakpoint$.next('xs');
    } else if (width >= 576 && width < 768) {
      this.mediaBreakpoint$.next('sm');
    } else if (width >= 768 && width < 992) {
      this.mediaBreakpoint$.next('md');
    } else if (width >= 992 && width < 1200) {
      this.mediaBreakpoint$.next('lg');
    } else if (width >= 1200 && width < 1600) {
      this.mediaBreakpoint$.next('xl');
    } else {
      this.mediaBreakpoint$.next('xxl');
    }
  }

}

Надеюсь, это кому-то поможет


Мой любимый ответ! Просто убедитесь, что вы добавили this.init () в конструктор, чтобы он работал.
Бен


4

Ответ очень простой. напишите приведенный ниже код

import { Component, OnInit, OnDestroy, Input } from "@angular/core";
// Import this, and write at the top of your .ts file
import { HostListener } from "@angular/core";

@Component({
 selector: "app-login",
 templateUrl: './login.component.html',
 styleUrls: ['./login.component.css']
})

export class LoginComponent implements OnInit, OnDestroy {
// Declare height and width variables
scrHeight:any;
scrWidth:any;

@HostListener('window:resize', ['$event'])
getScreenSize(event?) {
      this.scrHeight = window.innerHeight;
      this.scrWidth = window.innerWidth;
      console.log(this.scrHeight, this.scrWidth);
}

// Constructor
constructor() {
    this.getScreenSize();
}
}

3
@HostListener("window:resize", [])
public onResize() {
  this.detectScreenSize();
}

public ngAfterViewInit() {
    this.detectScreenSize();
}

private detectScreenSize() {
    const height = window.innerHeight;
    const width = window.innerWidth;
}

4
Всегда
объясняйте,

1

Для этого сценария вы можете использовать метод получения машинописного текста. Как это

public get width() {
  return window.innerWidth;
}

И используйте это в шаблоне следующим образом:

<section [ngClass]="{ 'desktop-view': width >= 768, 'mobile-view': width < 768 
}"></section>

Вам не понадобится обработчик событий для проверки изменения размера / размера окна, этот метод будет проверять размер каждый раз автоматически.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.