Để giải quyết vấn đề của bạn, bạn chỉ cần để có được và lưu trữ kích thước của div
trong một tài sản thành phần sau mỗi sự kiện thay đổi kích thước, và sử dụng tài sản đó trong mẫu. Bằng cách này, giá trị sẽ vẫn không đổi khi vòng phát hiện thay đổi thứ 2 chạy trong chế độ dev.
Tôi cũng khuyên bạn nên sử dụng @HostListener
thay vì thêm (window:resize)
vào mẫu của bạn. Chúng tôi sẽ sử dụng @ViewChild
để tham chiếu đến số div
. Và chúng tôi sẽ sử dụng móc vòng đời ngAfterViewInit()
để đặt giá trị ban đầu.
Quá xấu không hoạt động. Chúng tôi nhận được
Biểu thức đã thay đổi sau khi được kiểm tra. Giá trị trước đó: 'false'. Giá trị hiện tại: 'true'.
Các lỗi được phàn nàn về NgIf
biểu thức của chúng ta - lần đầu tiên nó chạy, divWidth
là 0, sau đó ngAfterViewInit()
chạy và thay đổi giá trị thành một cái gì đó khác hơn 0, sau đó vòng 2 phát hiện chạy thay đổi (trong dev chế độ). Rất may, có một giải pháp dễ dàng/biết đến, và đây là một chỉ vấn đề một lần, không phải là một vấn đề tiếp tục như thế nào trong OP:
ngAfterViewInit() {
// wait a tick to avoid one-time devMode
// unidirectional-data-flow-violation error
setTimeout(_ => this.divWidth = this.parentDiv.nativeElement.clientWidth);
}
Lưu ý rằng kỹ thuật này, chờ đợi một đánh dấu được ghi lại ở đây: https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#parent-to-view-child
Thông thường, trong ngAfterViewInit()
và ngAfterViewChecked()
, chúng tôi sẽ cần sử dụng mẹo setTimeout()
vì các phương pháp này được gọi sau khi chế độ xem của thành phần được soạn.
Đây là số đang hoạt động plunker.
Chúng tôi có thể cải thiện điều này. Tôi nghĩ rằng chúng ta nên điều tiết các sự kiện thay đổi kích thước như vậy mà phát hiện thay đổi góc chỉ chạy, nói rằng, mỗi 100-250ms, thay vào đó mỗi khi một sự kiện thay đổi kích thước xảy ra. Điều này sẽ ngăn ứng dụng bị chậm lại khi người dùng thay đổi kích thước cửa sổ, bởi vì ngay bây giờ, mọi sự kiện thay đổi kích thước sẽ làm thay đổi phát hiện chạy (hai lần trong chế độ dev). Bạn có thể xác minh điều này bằng cách thêm các phương pháp sau đây để các plunker trước:
ngDoCheck() {
console.log('change detection');
}
quan sát có thể dễ dàng sự kiện ga, vì vậy thay vì sử dụng @HostListener
liên kết với trường hợp thay đổi kích thước, chúng tôi sẽ tạo ra một quan sát được:
Observable.fromEvent(window, 'resize')
.throttleTime(200)
.subscribe(_ => this.divWidth = this.parentDiv.nativeElement.clientWidth);
Công việc này, nhưng ... trong khi thử nghiệm với điều đó, tôi đã phát hiện ra điều gì đó rất thú vị ... mặc dù chúng tôi điều chỉnh sự kiện thay đổi kích thước, phát hiện thay đổi góc vẫn chạy mỗi khi có sự kiện thay đổi kích thước. Tức là, việc điều chỉnh không ảnh hưởng đến tần suất thay đổi phát hiện chạy. (Tobias Bosch đã xác nhận điều này: https://github.com/angular/angular/issues/1773#issuecomment-102078250.)
Tôi chỉ muốn phát hiện thay đổi để chạy nếu sự kiện vượt qua thời gian điều tiết. Và tôi chỉ cần phát hiện thay đổi để chạy trên thành phần này. Giải pháp là để tạo ra các quan sát bên ngoài vùng kiễu góc, sau đó tự gọi phát hiện sự thay đổi bên trong gọi lại thuê bao:
constructor(private ngzone: NgZone, private cdref: ChangeDetectorRef) {}
ngAfterViewInit() {
// set initial value, but wait a tick to avoid one-time devMode
// unidirectional-data-flow-violation error
setTimeout(_ => this.divWidth = this.parentDiv.nativeElement.clientWidth);
this.ngzone.runOutsideAngular(() =>
Observable.fromEvent(window, 'resize')
.throttleTime(200)
.subscribe(_ => {
this.divWidth = this.parentDiv.nativeElement.clientWidth;
this.cdref.detectChanges();
})
);
}
Dưới đây là một công tác plunker.
Trong plunker tôi đã thêm counter
mà tôi tăng mỗi chu kỳ phát hiện thay đổi bằng móc vòng đời ngDoCheck()
. Bạn có thể thấy rằng phương thức này không được gọi là – giá trị bộ đếm không thay đổi về các sự kiện thay đổi kích thước.
detectChanges()
sẽ chạy phát hiện thay đổi đối với thành phần này và con của nó. Nếu bạn muốn chạy phát hiện thay đổi từ thành phần gốc (tức là, hãy chạy kiểm tra phát hiện thay đổi đầy đủ), sau đó sử dụng ApplicationRef.tick()
thay vào đó (điều này được nhận xét trong trình ngắt). Lưu ý rằng tick()
sẽ gây ra ngDoCheck()
để được gọi.
Đây là một câu hỏi hay.Tôi đã dành rất nhiều thời gian để thử các giải pháp khác nhau và tôi đã học được rất nhiều. Cảm ơn bạn đã đăng câu hỏi này.
Tôi không chắc tôi hiểu những gì bạn đang tìm kiếm ... nhưng ... Thứ nhất, tại sao bạn viết '* ngif =" ... '.Đây có thể là một cú pháp đúng (không bận tâm kiểm tra nó), nhưng tôi biết chắc chắn rằng' ng-if = "..." 'hoạt động khi điều kiện thử nghiệm nằm trong phạm vi của Góc Như vậy, bạn có thể thử thay đổi điều này và có một biến '$ scope' đang được cập nhật để cho phép kiểm tra như bạn muốn (tức là chiều rộng so với ngưỡng) – FDavidov
Xin chào David, cảm ơn vì bình luận của bạn. Angular/Angular2, nhưng tôi nghĩ ng-if & $ scope chỉ được sử dụng trong Angular và đã được thay thế trong Angular2. cô ấy giải thích mục tiêu của tôi nếu bạn quan tâm. Chúc mừng –
Rất tiếc !!! Đã bỏ lỡ "2". Lấy làm tiếc. Tôi sẽ gắn bó với Angular trong thời gian này :-). – FDavidov