Đối với một giải pháp cho vấn đề trọng tâm, bạn có thể tạo ra một chỉ thị thuộc tính, focusMe
:
import {Component, Directive, ElementRef} from 'angular2/core';
@Directive({
selector: '[focusMe]'
})
export class FocusDirective {
constructor(private el: ElementRef) {}
ngAfterViewInit() {
this.el.nativeElement.focus();
}
}
@Component({
selector: 'my-app',
directives: [FocusDirective],
template: `<h1>My First Angular 2 App</h1>
<button (click)="toggle()">toggle</button>
<input focusMe *ngIf="isVisible">
`
})
export class AppComponent {
constructor() { console.clear(); }
private isVisible = false;
toggle() {
this.isVisible = !this.isVisible;
}
}
Plunker
Cập nhật 1: Thêm giải pháp cho tính năng tái tập trung:
import {Component, Directive, ElementRef, Input} from 'angular2/core';
@Directive({
selector: '[focusMe]'
})
export class FocusMe {
@Input('focusMe') hasFocus: boolean;
constructor(private elementRef: ElementRef) {}
ngAfterViewInit() {
this.elementRef.nativeElement.focus();
}
ngOnChanges(changes) {
//console.log(changes);
if(changes.hasFocus && changes.hasFocus.currentValue === true) {
this.elementRef.nativeElement.focus();
}
}
}
@Component({
selector: 'my-app',
template: `<h1>My First Angular 2 App</h1>
<button (click)="showInput()">Make it visible</button>
<input *ngIf="inputIsVisible" [focusMe]="inputHasFocus">
<button (click)="focusInput()" *ngIf="inputIsVisible">Focus it</button>
`,
directives:[FocusMe]
})
export class AppComponent {
private inputIsVisible = false;
private inputHasFocus = false;
constructor() { console.clear(); }
showInput() {
this.inputIsVisible = true;
}
focusInput() {
this.inputHasFocus = true;
setTimeout(() => this.inputHasFocus = false, 50);
}
}
Plunker
Một thay thế cho việc sử dụng setTimeout()
để thiết lập lại tài sản tập trung để false
sẽ tạo ra một sự kiện/tài sản đầu ra trên FocusDirective và emit()
sự kiện khi gọi focus()
. Sau đó AppComponent sẽ lắng nghe sự kiện đó và thiết lập lại thuộc tính focus.
Cập nhật 2: Dưới đây là một cách thay thế/tốt hơn để thêm tính năng lấy nét lại, sử dụng ViewChild. Chúng ta không cần theo dõi trạng thái lấy nét theo cách này, cũng như chúng ta không cần một thuộc tính đầu vào trên chỉ thị FocusMe.
import {Component, Directive, ElementRef, Input, ViewChild} from 'angular2/core';
@Directive({
selector: '[focusMe]'
})
export class FocusMe {
constructor(private elementRef: ElementRef) {}
ngAfterViewInit() {
// set focus when element first appears
this.setFocus();
}
setFocus() {
this.elementRef.nativeElement.focus();
}
}
@Component({
selector: 'my-app',
template: `<h1>My First Angular 2 App</h1>
<button (click)="showInput()">Make it visible</button>
<input *ngIf="inputIsVisible" focusMe>
<button (click)="focusInput()" *ngIf="inputIsVisible">Focus it</button>
`,
directives:[FocusMe]
})
export class AppComponent {
@ViewChild(FocusMe) child;
private inputIsVisible = false;
constructor() { console.clear(); }
showInput() {
this.inputIsVisible = true;
}
focusInput() {
this.child.setFocus();
}
}
Plunker
Cập nhật 3: Dưới đây là thêm một thay thế mà không đòi hỏi một chỉ thị, mà vẫn sử dụng ViewChild, nhưng chúng tôi truy cập vào đứa trẻ qua mẫu biến cục bộ chứ không phải là một chỉ thị thuộc tính (nhờ @alexpods cho the tip):
import {Component, ViewChild, NgZone} from 'angular2/core';
@Component({
selector: 'my-app',
template: `<h1>Focus test</h1>
<button (click)="showInput()">Make it visible</button>
<input #input1 *ngIf="input1IsVisible">
<button (click)="focusInput1()" *ngIf="input1IsVisible">Focus it</button>
`,
})
export class AppComponent {
@ViewChild('input1') input1ElementRef;
private input1IsVisible = false;
constructor(private _ngZone: NgZone) { console.clear(); }
showInput() {
this.input1IsVisible = true;
// Give ngIf a chance to render the <input>.
// Then set the focus, but do this outside the Angualar zone to be efficient.
// There is no need to run change detection after setTimeout() runs,
// since we're only focusing an element.
this._ngZone.runOutsideAngular(() => {
setTimeout(() => this.focusInput1(), 0);
});
}
setFocus(elementRef) {
elementRef.nativeElement.focus();
}
ngDoCheck() {
// if you remove the ngZone stuff above, you'll see
// this log 3 times instead of 1 when you click the
// "Make it visible" button.
console.log('doCheck');
}
focusInput1() {
this.setFocus(this.input1ElementRef);
}
}
Plunker
Cập nhật 4: Tôi cập nhật mã trong Cập nhật 3 sử dụng NgZone để chúng ta không gây ra thuật toán phát hiện sự thay đổi góc để chạy sau khi setTimeout()
kết thúc. (Để biết thêm về phát hiện thay đổi, hãy xem this answer).
Cập nhật 5: Tôi đã cập nhật mã trong trình chỉnh sửa ở trên để sử dụng Trình kết xuất để đảm bảo an toàn cho công nhân web. Truy cập focus()
trực tiếp trên nativeElement
không được khuyến khích.
focusInput1() {
this._renderer.invokeElementMethod(
this.input1ElementRef.nativeElement, 'focus', []);
}
Tôi đã học được rất nhiều từ câu hỏi này.
Xem thêm https://github.com/angular/angular/issues/6179 –
Tôi đã điền đầy đủ vấn đề về repo góc vì đó là lỗi nếu chúng tôi xem xét tài liệu thực tế nêu rõ "Chúng tôi có thể tham chiếu biến mẫu cục bộ trên cùng một yếu tố, trên một phần tử anh chị em, hoặc trên bất kỳ phần tử con nào của nó. –