Thay đổi kích thước cửa sổ góc


232

Tôi muốn thực hiện một số tác vụ dựa trên sự kiện kích thước lại cửa sổ (khi tải và động).

Hiện tại tôi có DOM của mình như sau:

<div id="Harbour">
    <div id="Port" (window:resize)="onResize($event)" >
        <router-outlet></router-outlet>
    </div>
</div>

Sự kiện này chính xác

export class AppComponent {
   onResize(event) {
        console.log(event);
    }
}

Làm cách nào để truy xuất Chiều rộng và Chiều cao từ đối tượng sự kiện này?

Cảm ơn.


6
Không thực sự là một câu hỏi góc cạnh. nhìn vào đối tượng cửa sổ . Bạn có thể lấy nó innerHeightinnerWidthtài sản ..
Sasxa

1
@Sasxa là chính xác, bạn chỉ cần làmconsole.log(event.target.innerWidth )
Pankaj Parkar

Cảm ơn về thông tin Sasxa / Pankaj - Tôi không chắc liệu đó chỉ là một thứ javascript đơn giản hay một thứ Bản in hay một sự kiện Angular. Tôi đang leo lên một đường cong học tập rất dốc cho bản thân mình ở đây và đánh giá cao đầu vào của bạn.
DanAbdn

Câu trả lời:


527
<div (window:resize)="onResize($event)"
onResize(event) {
  event.target.innerWidth;
}

hoặc sử dụng trình trang trí HostListener :

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

Mục tiêu toàn cầu được hỗ trợ là window, document, và body.

Cho đến khi https://github.com/angular/angular/issues/13248 được triển khai trong Angular, tốt hơn hết là bạn nên đăng ký các sự kiện DOM và sử dụng RXJS để giảm số lượng sự kiện như trong một số câu trả lời khác.


15
Có tài liệu nào về cú pháp bạn sử dụng: window: resize không?
Clement

3
Chính xác. Bạn có thể sử dụng document, windowbody github.com/angular/angular/blob/...
Günter Zöchbauer

5
câu trả lời hoàn hảo .. tôi tin rằng @hostListener là cách sạch hơn :) nhưng trước tiên hãy đảm bảo nhập HostListener bằng cách sử dụngimport { Component, OnInit, HostListener } from '@angular/core';
Gaurav Sharma

4
Mẹo nhanh: Nếu bạn cũng muốn kích hoạt tải lần đầu tiên, hãy triển khai ngAfterViewInit từ @ angular / core. angular.io/api/core/AfterViewInit
Zymotik

7
Tuy nhiên, chắc chắn, đối với những người muốn biết HostListener hoạt động như thế nào với debounceTime, hãy theo liên kết bên dưới plnkr.co/edit/3J0dcDaLTJBxkzo8Akyg?p=preview
jcdsr

65

Câu trả lời của @ Günter là chính xác. Tôi chỉ muốn đề xuất một phương pháp khác.

Bạn cũng có thể thêm liên kết máy chủ bên trong @Component()-decorator. Bạn có thể đặt sự kiện và lệnh gọi hàm mong muốn trong thuộc tính siêu dữ liệu máy chủ như sau:

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  host: {
    '(window:resize)': 'onResize($event)'
  }
})
export class AppComponent{
   onResize(event){
     event.target.innerWidth; // window width
   }
}

2
Tôi đã thử mọi phương pháp trên trang này và dường như không có phương pháp nào hoạt động. Có bất kỳ tài liệu chính thức về điều này.
Cà chua

Làm thế nào là chiều cao khung nhìn thu được trên tải?
Giridhar Karnik

@GiridharKarnik, bạn đã thử làm một window.innerWidthbên trong ngOnInit, hoặc ngAfterViewInitphương pháp?
Giăng

@Tomato Tham chiếu API có thể được tìm thấy ở đây Nhiều tài liệu tham khảo được tự động tạo (tôi đoán) và thiếu ví dụ hoặc giải thích chi tiết. Một số tài liệu tham khảo api có rất nhiều ví dụ. Tôi không thể tìm thấy một ví dụ cụ thể từ các tài liệu về điều này mặc dù. Có lẽ nó được giấu ở đâu đó: P
John

1
đây là một tài liệu tham khảo về cách sử dụng nó
Anand Rockzz

52

Tôi biết điều này đã được hỏi từ lâu, nhưng có một cách tốt hơn để làm điều này bây giờ! Tôi không chắc chắn nếu có ai sẽ nhìn thấy câu trả lời này mặc dù. Rõ ràng hàng nhập khẩu của bạn:

import { fromEvent, Observable, Subscription } from "rxjs";

Sau đó, trong thành phần của bạn:

resizeObservable$: Observable<Event>
resizeSubscription$: Subscription

ngOnInit() {
    this.resizeObservable$ = fromEvent(window, 'resize')
    this.resizeSubscription$ = this.resizeObservable$.subscribe( evt => {
      console.log('event: ', evt)
    })
}

Sau đó hãy chắc chắn để hủy đăng ký phá hủy!

ngOnDestroy() {
    this.resizeSubscription$.unsubscribe()
}

Cách duy nhất đã làm việc cho tôi. Cảm ơn!! :-) ... Tôi chỉ phải điều chỉnh nhập khẩu của bạn. Có lẽ rxjs của tôi mới hơn:import { fromEvent, Observable,Subscription } from "rxjs";
Jette

Tôi có thể thêm debounce (1000) ở đâu?
Deepak Thomas

3
Xin lỗi vì trả lời trễ: để thêm gỡ lỗi, bạn sẽ muốn sử dụngthis.resizeSubscription$ = this.resizeObservable$.pipe(debounceTime(1000)).subscribe( evt => { console.log('event: ', evt) })
Chris Stanley

41

Cách chính xác để làm điều này là sử dụng lớp EventManager để liên kết sự kiện. Điều này cho phép mã của bạn hoạt động trong các nền tảng thay thế, ví dụ như kết xuất phía máy chủ với Angular Universal.

import { EventManager } from '@angular/platform-browser';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import { Injectable } from '@angular/core';

@Injectable()
export class ResizeService {

  get onResize$(): Observable<Window> {
    return this.resizeSubject.asObservable();
  }

  private resizeSubject: Subject<Window>;

  constructor(private eventManager: EventManager) {
    this.resizeSubject = new Subject();
    this.eventManager.addGlobalEventListener('window', 'resize', this.onResize.bind(this));
  }

  private onResize(event: UIEvent) {
    this.resizeSubject.next(<Window>event.target);
  }
}

Việc sử dụng trong một thành phần đơn giản như việc thêm dịch vụ này với tư cách là nhà cung cấp vào app.module của bạn và sau đó nhập nó vào hàm tạo của một thành phần.

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'my-component',
  template: ``,
  styles: [``]
})
export class MyComponent implements OnInit {

  private resizeSubscription: Subscription;

  constructor(private resizeService: ResizeService) { }

  ngOnInit() {
    this.resizeSubscription = this.resizeService.onResize$
      .subscribe(size => console.log(size));
  }

  ngOnDestroy() {
    if (this.resizeSubscription) {
      this.resizeSubscription.unsubscribe();
    }
  }
}

Điều này không bao giờ kích hoạt trên điện thoại di động như tôi có thể nói. Làm thế nào để bạn có được kích thước cửa sổ ban đầu với phương pháp này?
dùng3170530

Điện thoại di động không có windowđối tượng, giống như máy chủ không có window. Tôi không quen thuộc với các cấu hình di động khác nhau nhưng bạn có thể dễ dàng điều chỉnh mã ở trên để liên kết với trình nghe sự kiện toàn cầu chính xác
cgatian

@cgatian Tôi là một người mới nhưng đây có vẻ là câu trả lời đúng. Thật không may là tôi không có may mắn làm cho đăng ký của tôi Đăng nhập thành phần. Bạn có thể thêm vào câu trả lời làm thế nào để đăng ký cái này trong một thành phần để người ta có thể xem các bản cập nhật không?
Matthew Harwood

@cgatian Tôi sẽ làm một plunker nhưng điều này dường như không hoạt động. Bộ lọc trong dịch vụ có vẻ kỳ lạ tho stackoverflow.com/q/46397531/1191635
Matthew Harwood

3
@cgatian Mobile does not have a window object.... tại sao bạn nghĩ trình duyệt di động không có đối tượng cửa sổ?
Drenai

31

Đây là một cách tốt hơn để làm điều đó. Dựa trên câu trả lời của Birowsky .

Bước 1: Tạo một angular servicevới RxJS Observables .

import { Injectable } from '@angular/core';
import { Observable, BehaviorSubject } from 'rxjs';

@Injectable()
export class WindowService {
    height$: Observable<number>;
    //create more Observables as and when needed for various properties
    hello: string = "Hello";
    constructor() {
        let windowSize$ = new BehaviorSubject(getWindowSize());

        this.height$ = (windowSize$.pluck('height') as Observable<number>).distinctUntilChanged();

        Observable.fromEvent(window, 'resize')
            .map(getWindowSize)
            .subscribe(windowSize$);
    }

}

function getWindowSize() {
    return {
        height: window.innerHeight
        //you can sense other parameters here
    };
};

Bước 2: Tiêm ở trên servicevà đăng ký bất kỳ thứ gì Observablesđược tạo trong dịch vụ bất cứ nơi nào bạn muốn nhận sự kiện thay đổi kích thước cửa sổ.

import { Component } from '@angular/core';
//import service
import { WindowService } from '../Services/window.service';

@Component({
    selector: 'pm-app',
    templateUrl: './componentTemplates/app.component.html',
    providers: [WindowService]
})
export class AppComponent { 

    constructor(private windowService: WindowService) {

        //subscribe to the window resize event
        windowService.height$.subscribe((value:any) => {
            //Do whatever you want with the value.
            //You can also subscribe to other observables of the service
        });
    }

}

Một sự hiểu biết đúng đắn về Lập trình Phản ứng sẽ luôn giúp khắc phục các vấn đề khó khăn. Hy vọng điều này sẽ giúp được ai đó.


Tôi tin rằng đây là một lỗi: this.height $ = (windowSize $ .pluck ('height') là Observable <number>). DifferUntilChanged (); Observable <number>). DifferUntilChanged (); có vẻ như bạn đã dán trong phần riêng
biệtUntilChanged

Tôi đã không nhận được bạn, xin vui lòng.
Giridhar Karnik

Phát hiện thay đổi sẽ không bị từ chối khi bạn thực hiện sự kiện này bên ngoài Angular, tin rằng đó là ý anh ấy.
Mark Pieszak - Trilon.io

1
Tôi đã gặp lỗi khi nói 'nhổ' không tồn tại trên loại BehaviorSubject. Thay đổi mã thành this.height $ = windowSize $ .map (x => x.height) đã làm việc cho tôi.
Matt Sugden

@GiridharKamik Bạn có thể cung cấp giải pháp đăng ký chiều rộng và chiều cao cùng một lúc không, chúng tôi có thể đăng ký cả chiều rộng, chiều cao trong 1 đăng ký đơn giản
mã hóa

11

Tôi chưa thấy ai nói chuyện về MediaMatchercủa angular/cdk.

Bạn có thể định nghĩa một MediaQuery và đính kèm một trình nghe cho nó - sau đó bất cứ nơi nào trên mẫu (hoặc ts) của bạn, bạn có thể gọi công cụ nếu Matcher được khớp. LiveExample

App.Component.ts

import {Component, ChangeDetectorRef} from '@angular/core';
import {MediaMatcher} from '@angular/cdk/layout';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  mobileQuery: MediaQueryList;

  constructor(changeDetectorRef: ChangeDetectorRef, media: MediaMatcher) {
    this.mobileQuery = media.matchMedia('(max-width: 600px)');
    this._mobileQueryListener = () => changeDetectorRef.detectChanges();
    this.mobileQuery.addListener(this._mobileQueryListener);
  }

  private _mobileQueryListener: () => void;

  ngOnDestroy() {
    this.mobileQuery.removeListener(this._mobileQueryListener);
  }

}

App.Component.Html

<div [class]="mobileQuery.matches ? 'text-red' : 'text-blue'"> I turn red on mobile mode 
</div>

App.Component.css

.text-red { 
   color: red;
}

.text-blue {
   color: blue;
}

nguồn: https : // m Material.angular.io/components/sidenav/overview


6

Giả sử rằng <600px có nghĩa là thiết bị di động đối với bạn, bạn có thể sử dụng điều này có thể quan sát được và đăng ký nó:

Đầu tiên chúng ta cần kích thước cửa sổ hiện tại. Vì vậy, chúng tôi tạo ra một quan sát chỉ phát ra một giá trị duy nhất: kích thước cửa sổ hiện tại.

initial$ = Observable.of(window.innerWidth > 599 ? false : true);

Sau đó, chúng ta cần tạo một cái khác có thể quan sát được, để chúng ta biết khi nào kích thước cửa sổ được thay đổi. Đối với điều này, chúng ta có thể sử dụng toán tử "fromEvent". Để tìm hiểu thêm về các nhà khai thác của rxjs, vui lòng truy cập: rxjs

resize$ = Observable.fromEvent(window, 'resize').map((event: any) => {
  return event.target.innerWidth > 599 ? false : true;
 });

Hợp nhất hai luồng này để nhận được quan sát của chúng tôi:

mobile$ = Observable.merge(this.resize$, this.initial$).distinctUntilChanged();

Bây giờ bạn có thể đăng ký nó như thế này:

mobile$.subscribe((event) => { console.log(event); });

Nhớ hủy đăng ký :)


5

Có dịch vụ ViewportRuler trong CDK góc. Nó chạy bên ngoài vùng và cũng hoạt động với kết xuất phía máy chủ.


2
đây sẽ là câu trả lời được chấp nhận Có mọi thứ cần thiết + đây là chức năng sẵn có CDK góc cạnh.
Deniss M.

3

Dựa trên giải pháp của @cgatian tôi sẽ đề xuất cách đơn giản hóa sau:

import { EventManager } from '@angular/platform-browser';
import { Injectable, EventEmitter } from '@angular/core';

@Injectable()
export class ResizeService {

  public onResize$ = new EventEmitter<{ width: number; height: number; }>();

  constructor(eventManager: EventManager) {
    eventManager.addGlobalEventListener('window', 'resize',
      e => this.onResize$.emit({
        width: e.target.innerWidth,
        height: e.target.innerHeight
      }));
  }
}

Sử dụng:

import { Component } from '@angular/core';
import { ResizeService } from './resize-service';

@Component({
  selector: 'my-component',
  template: `{{ rs.onResize$ | async | json }}`
})
export class MyComponent {
  constructor(private rs: ResizeService) { }
}

Tôi thấy đây là giải pháp tốt nhất, tuy nhiên, nó chỉ hoạt động khi cửa sổ được thay đổi kích thước, nhưng không phải khi tải hoặc khi bộ định tuyến thay đổi. Bạn có biết, làm thế nào để áp dụng với thay đổi bộ định tuyến, tải lại hoặc tải?
jcdsr

Bạn có thể thêm một hàm vào dịch vụ và kích hoạt nó trong thành phần @jcdsr: getScreenSize () {this.onResize $ .emit ({width: window.innerWidth, height: window.innerHeight}); }
DanielWaw

3

Đây không phải là câu trả lời chính xác cho câu hỏi nhưng nó có thể giúp ai đó cần phát hiện thay đổi kích thước trên bất kỳ yếu tố nào.

Tôi đã tạo một thư viện thêm resizedsự kiện vào bất kỳ yếu tố nào - Sự kiện thay đổi kích thước góc .

Nó sử dụng nội bộ ResizeSensortừ CSS Element Queries .

Ví dụ sử dụng

HTML

<div (resized)="onResized($event)"></div>

TypeScript

@Component({...})
class MyComponent {
  width: number;
  height: number;

  onResized(event: ResizedEvent): void {
    this.width = event.newWidth;
    this.height = event.newHeight;
  }
}

nếu bạn muốn phát hiện thay đổi kích thước cửa sổ thì Angular Material Breakpoint Observer đã xử lý vật
Darren Street

Nhưng điều này không chỉ phát hiện thay đổi kích thước cửa sổ, mà bất kỳ yếu tố nào thay đổi kích thước.
Martin Volek

2

Tôi đã viết lib này để tìm một khi thay đổi kích thước ranh giới thành phần (thay đổi kích thước) trong Angular, điều này có thể giúp người khác. Bạn có thể đặt nó trên thành phần gốc, sẽ làm tương tự như thay đổi kích thước cửa sổ.

Bước 1: Nhập mô-đun

import { BoundSensorModule } from 'angular-bound-sensor';

@NgModule({
  (...)
  imports: [
    BoundSensorModule,
  ],
})
export class AppModule { }

Bước 2: Thêm chỉ thị như bên dưới

<simple-component boundSensor></simple-component>

Bước 3: Nhận chi tiết kích thước ranh giới

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

@Component({
  selector: 'simple-component'
  (...)
})
class SimpleComponent {
  @HostListener('resize', ['$event'])
  onResize(event) {
    console.log(event.detail);
  }
}

1

Trên Angular2 (2.1.0) tôi sử dụng ngZone để ghi lại sự kiện thay đổi màn hình.

Hãy xem ví dụ:

import { Component, NgZone } from '@angular/core';//import ngZone library
...
//capture screen changed inside constructor
constructor(private ngZone: NgZone) {
    window.onresize = (e) =>
    {
        ngZone.run(() => {
            console.log(window.innerWidth);
            console.log(window.innerHeight);
        });
    };
}

Tôi hy vọng sự giúp đỡ này!


1

Mã dưới đây cho phép quan sát bất kỳ thay đổi kích thước cho bất kỳ div nhất định trong Angular.

<div #observed-div>
</div>

sau đó trong Thành phần:

oldWidth = 0;
oldHeight = 0;

@ViewChild('observed-div') myDiv: ElementRef;
ngAfterViewChecked() {
  const newWidth = this.myDiv.nativeElement.offsetWidth;
  const newHeight = this.myDiv.nativeElement.offsetHeight;
  if (this.oldWidth !== newWidth || this.oldHeight !== newHeight)
    console.log('resized!');

  this.oldWidth = newWidth;
  this.oldHeight = newHeight;
}

Tôi muốn thay đổi một varibale từ counter = 6 thành Count = 0 ở độ rộng tối đa 767px, Làm thế nào để tôi làm điều đó?
Thanveer Shah

0

tất cả các giải pháp không hoạt động với phía máy chủ hoặc phổ quát góc


0

Tôi đã kiểm tra hầu hết các câu trả lời. sau đó quyết định kiểm tra tài liệu Angular trên Bố cục .

Angular có Observer riêng để phát hiện các kích thước khác nhau và rất dễ thực hiện trong thành phần hoặc Dịch vụ.

một ví dụ đơn giản sẽ là:

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

@Component({...})
class MyComponent {
  constructor(breakpointObserver: BreakpointObserver) {
    breakpointObserver.observe([
      Breakpoints.HandsetLandscape,
      Breakpoints.HandsetPortrait
    ]).subscribe(result => {
      if (result.matches) {
        this.activateHandsetLayout();
      }
    });
  }
}

hy vọng nó giúp

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.