Phát hiện thay đổi kích thước cửa sổ thời gian thực trong Angular 4


118

Tôi đã cố gắng xây dựng một thanh điều hướng đáp ứng và không muốn sử dụng truy vấn phương tiện, vì vậy tôi định sử dụng *ngIFkích thước cửa sổ làm tiêu chí. Nhưng tôi đã gặp phải một vấn đề là tôi không thể tìm thấy bất kỳ phương pháp hoặc tài liệu nào về phát hiện kích thước cửa sổ Angular 4. Tôi cũng đã thử phương pháp JavaScript, nhưng nó không được hỗ trợ.

Tôi cũng đã thử những cách sau :

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

... được sử dụng trong ion.

screen.availHeight, nhưng vẫn không thành công.


1
Về cái gì platform? Đây là về Ionic?
Günter Zöchbauer

@ Günter Zöchbauer Nền tảng có góc cạnh, chỉ muốn đề cập đến các mã mà tôi đã thử.
Ronit Oommen,

1
Platformlà một dịch vụ ion. Vì vậy, tôi đoán đó là một dự án Ionic?
robbannn 27/07/17


@BlackBeard Tôi không nghĩ nó trùng lặp do Angular 2 và 4 khác nhau nhiều như thế nào.
tehlivi

Câu trả lời:


261

Để có được nó trên init

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

Nếu bạn muốn cập nhật nó khi thay đổi kích thước:

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

2
this.innerWidth = event.target.innerWidth; ... có thể hiệu quả hơn, tạo ra kết quả tương tự
danday74

2
Cũng khuyến nghị điều này trong hàm tạo nếu bạn đang sử dụng lodash ... this.onResize = debounce (this.onResize, 150, {lead: false, trailing: true}) ... để ngăn phương thức onResize được gọi quá thường xuyên .. . bạn sẽ cần ... nhập {debounce} từ 'lodash'
danday74,

Tôi nghĩ thích sử dụng ngAfterViewInitphương pháp life hook thay vì phương pháp ngOnInit life hook
ahmed hamdy

39

Nếu bạn muốn phản ứng trên các điểm ngắt nhất định (ví dụ: làm điều gì đó nếu chiều rộng nhỏ hơn 768px), bạn cũng có thể sử dụng BreakpointObserver:

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

{ ... }

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

hoặc thậm chí lắng nghe những thay đổi đối với điểm ngắt đó:

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

nếu bạn muốn đóng vai trò chỉ khi người quan sát phù hợp với tiêu chí mà bạn đã thêm vào bên trong đăng ký này if (result.matches)nếu không nó sẽ gọi ngay cả khi nó không
karoluS

1
@karoluS: Tất nhiên là có. Tôi đã chỉnh sửa câu trả lời của mình để làm rõ điều đó. Cảm ơn bạn.
Jeremy Benks

Có vẻ như điều này cdkcó sự phụ thuộc ngang hàng vào phiên bản cụ thể của góc. Like 7 cho cái mới nhất. Dù sao tôi có thể sử dụng điều này cho phiên bản cũ hơn (góc 4 như trong câu hỏi)?
LeOn - Han Li

@Leon li: Tôi thực sự sử dụng góc 7, đúng vậy. Tuy nhiên: Theo như tôi biết thì bạn cũng có thể sử dụng cdk trong góc 4. Theo bài đăng trên blog này, bạn cần cdk 2.x. Theo như tôi biết, điều này phải được cài đặt bằng tay và với phiên bản được quy định như thế này: NPM @ góc / cdk @ 4
Jeremy Benks

@JeremyBenks Y, chúng tôi đang sử dụng ng 4.2.6cụ thể. Không thể tìm thấy điểm chênh lệch cdk 2.x trên đó, chỉ có 4.1.x và 4.3.x. Dù sao cũng cảm ơn!
LeOn - Han Li

9

Nếu bạn muốn các thành phần của mình vẫn có thể kiểm tra dễ dàng, bạn nên bọc đối tượng cửa sổ chung trong một Dịch vụ Angular:

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

@Injectable()
export class WindowService {

  get windowRef() {
    return window;
  }

}

Sau đó, bạn có thể tiêm nó giống như bất kỳ dịch vụ nào khác:

constructor(
    private windowService: WindowService
) { }

Và tiêu thụ ...

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

2
Tôi không thể thấy điểm mấu chốt của việc thực hiện một dịch vụ để làm chính xác những gì nó đã có trong tay. window.innerWidth.
Rodrigo

1
Đầu tiên DI là cách Angular và làm cho các phụ thuộc của một thành phần / chỉ thị rõ ràng hơn. Nhưng điểm chính được đề cập ở đây là làm cho mã sử dụng dịch vụ dễ kiểm tra hơn. Sử dụng cách tiếp cận này, WindowService có thể bị chế nhạo trong bất kỳ bài kiểm tra nào được viết cho các thành phần sử dụng dịch vụ.
Kildareflare

9

Tài liệu cho Platform width()height(), nó nói rằng các phương pháp này sử dụng window.innerWidthwindow.innerHeighttương ứng. Nhưng việc sử dụng các phương pháp được ưu tiên hơn vì các thứ nguyên là các giá trị được lưu trong bộ nhớ cache, điều này làm giảm cơ hội đọc nhiều DOM và tốn kém.

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();
    });
}

Làm thế nào để nhận được widthcác windowliên quan đến DOM? Về mặt logic, nó không nên phụ thuộc vào cây dom trông như thế nào.
Shahryar Saljoughi

6

Đây là một ví dụ về dịch vụ mà tôi sử dụng.

Bạn có thể nhận được chiều rộng màn hình bằng cách đăng ký screenWidth$hoặc thông qua screenWidth$.value.

Điều tương tự đối với mediaBreakpoint$(hoặc 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');
    }
  }

}

Hy vọng điều này sẽ giúp ai đó


Câu trả lời yêu thích của tôi! Chỉ cần đảm bảo rằng bạn thêm this.init () trong hàm tạo để nó hoạt động.
Ben


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

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

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

3
Luôn giải thích tại sao điều này có thể là giải pháp đúng
thedp

3

Câu trả lời rất đơn giản. viết mã dưới đây

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();
}
}

1

Bạn có thể sử dụng phương thức typecript getter cho trường hợp này. Như thế này

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

Và sử dụng nó trong mẫu như thế này:

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

Bạn sẽ không cần bất kỳ trình xử lý sự kiện nào để kiểm tra thay đổi kích thước / của cửa sổ, phương pháp này sẽ tự động kiểm tra kích thước mọi lúc.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.