Renderer устарел в Angular 4.0.0-rc.1, прочтите обновление ниже
Angular2 способ заключается в использовании listen
или listenGlobal
от видеообработки
Например, если вы хотите добавить событие щелчка к компоненту, вы должны использовать Renderer и ElementRef (это также дает вам возможность использовать ViewChild или что-нибудь, что извлекает nativeElement
)
constructor(elementRef: ElementRef, renderer: Renderer) {
renderer.listen(elementRef.nativeElement, 'click', (event) => {
})
);
Вы можете использовать listenGlobal
это даст вам доступ к document
, body
и т.д.
renderer.listenGlobal('document', 'click', (event) => {
});
Обратите внимание , что с beta.2 как listen
и listenGlobal
возвращает функцию для удаления слушателя (см отличий раздела из журнала изменений для beta.2). Это сделано для того, чтобы избежать утечки памяти в больших приложениях (см. № 6686 ).
Итак, чтобы удалить динамически добавленного слушателя, мы должны назначить listen
или listenGlobal
переменной, которая будет содержать возвращаемую функцию, а затем мы ее выполним.
listenFunc: Function;
globalListenFunc: Function;
constructor(elementRef: ElementRef, renderer: Renderer) {
this.listenFunc = renderer.listen(elementRef.nativeElement, 'click', (event) => {
});
this.globalListenFunc = renderer.listenGlobal('document', 'click', (event) => {
});
}
ngOnDestroy() {
this.listenFunc();
this.globalListenFunc();
}
Вот plnkr с примером работы. Пример содержит использование listen
и listenGlobal
.
Использование RendererV2 с Angular 4.0.0-rc.1 + (Renderer2 начиная с 4.0.0-rc.3)
25.02.2017 : Renderer
устарело, теперь мы должны использовать RendererV2
(см. Строку ниже). Смотрите коммит .
03.10.2017 : RendererV2
переименован в Renderer2
. Смотрите критические изменения .
RendererV2
больше не имеет listenGlobal
функции для глобальных событий (документ, тело, окно). У него есть только listen
функция, которая выполняет обе функции.
Для справки, я копирую и вставляю исходный код реализации DOM Renderer, поскольку он может измениться (да, это угловой!).
listen(target: 'window'|'document'|'body'|any, event: string, callback: (event: any) => boolean):
() => void {
if (typeof target === 'string') {
return <() => void>this.eventManager.addGlobalEventListener(
target, event, decoratePreventDefault(callback));
}
return <() => void>this.eventManager.addEventListener(
target, event, decoratePreventDefault(callback)) as() => void;
}
Как видите, теперь он проверяет, передаем ли мы строку (документ, тело или окно), и в этом случае он будет использовать внутреннюю addGlobalEventListener
функцию. В любом другом случае, когда мы передаем элемент (nativeElement), он будет использовать простойaddEventListener
Чтобы удалить слушателя, он такой же, как и Renderer
в angular 2.x. listen
возвращает функцию, затем вызывает эту функцию.
пример
let global = this.renderer.listen('document', 'click', (evt) => {
console.log('Clicking the document', evt);
})
let simple = this.renderer.listen(this.myButton.nativeElement, 'click', (evt) => {
console.log('Clicking the button', evt);
});
global();
simple();
plnkr с Angular 4.0.0-rc.1 с использованием RendererV2
plnkr с Angular 4.0.0-rc.3 с использованием Renderer2
host
используются.ngOnDestroy
кода, обаlisten
иlistenGlobal
возвращают функцию, которая при вызове / выполнении слушателя удаляется. Итак, как вы видитеthis.func
, удерживает функцию, возвращаемуюrenderer.listen
и когда я этоthis.func()
делаю, я удаляю слушателя. То же самое и сlistenGlobal
.Я также считаю это крайне запутанным. как указывает @EricMartinez, Renderer2 listen () возвращает функцию для удаления слушателя:
ƒ () { return element.removeEventListener(eventName, /** @type {?} */ (handler), false); }
Если я добавляю слушателя
this.listenToClick = this.renderer.listen('document', 'click', (evt) => { alert('Clicking the document'); })
Я ожидал, что моя функция выполнит то, что я задумал, а не полную противоположность, а именно удаление слушателя.
// I´d expect an alert('Clicking the document'); this.listenToClick(); // what you actually get is removing the listener, so nothing...
В данном сценарии было бы разумнее назвать его так:
// Add listeners let unlistenGlobal = this.renderer.listen('document', 'click', (evt) => { console.log('Clicking the document', evt); }) let removeSimple = this.renderer.listen(this.myButton.nativeElement, 'click', (evt) => { console.log('Clicking the button', evt); });
Для этого должна быть веская причина, но, на мой взгляд, это вводит в заблуждение и не интуитивно понятно.
источник
ngOnDestroy
метода. Признаюсь, сначала это может показаться запутанным, но на самом деле это очень полезная функция. Как еще убрать за собой?Вот мой обходной путь:
Я создал библиотеку с Angular 6. Я добавил общий компонент
commonlib-header
который так используется во внешнем приложении.Обратите внимание на
serviceReference
класс (внедренный в компонент,constructor(public serviceReference: MyService)
который используетcommonlib-header
), содержащийstringFunctionName
метод:<commonlib-header [logo]="{ src: 'assets/img/logo.svg', alt: 'Logo', href: '#' }" [buttons]="[{ index: 0, innerHtml: 'Button', class: 'btn btn-primary', onClick: [serviceReference, 'stringFunctionName', ['arg1','arg2','arg3']] }]"> </common-header>
Библиотечный компонент запрограммирован так. В
onClick(fn: any)
метод добавлено динамическое событие :export class HeaderComponent implements OnInit { _buttons: Array<NavItem> = [] @Input() set buttons(buttons: Array<any>) { buttons.forEach(navItem => { let _navItem = new NavItem(navItem.href, navItem.innerHtml) _navItem.class = navItem.class _navItem.onClick = navItem.onClick // this is the array from the component @Input properties above this._buttons[navItem.index] = _navItem }) } constructor() {} ngOnInit() {} onClick(fn: any){ let ref = fn[0] let fnName = fn[1] let args = fn[2] ref[fnName].apply(ref, args) }
Многоразовые
header.component.html
:<div class="topbar-right"> <button *ngFor="let btn of _buttons" class="{{ btn.class }}" (click)="onClick(btn.onClick)" [innerHTML]="btn.innerHtml | keepHtml"></button> </div>
источник
Я добавлю пример StackBlitz и комментарий к ответу @tahiche.
Возвращаемое значение - это функция для удаления прослушивателя событий после того, как вы его добавили. Считается хорошей практикой удалять прослушиватели событий, когда они вам больше не нужны. Таким образом, вы можете сохранить это возвращаемое значение и вызвать его внутри своего
ngOnDestroy
метода.Признаюсь, сначала это может показаться запутанным, но на самом деле это очень полезная функция. Как еще можно убрать за собой?
export class MyComponent implements OnInit, OnDestroy { public removeEventListener: () => void; constructor( private renderer: Renderer2, private elementRef: ElementRef ) { } public ngOnInit() { this.removeEventListener = this.renderer.listen(this.elementRef.nativeElement, 'click', (event) => { if (event.target instanceof HTMLAnchorElement) { // Prevent opening anchors the default way event.preventDefault(); // Your custom anchor click event handler this.handleAnchorClick(event); } }); } public ngOnDestroy() { this.removeEventListener(); } }
Вы можете найти StackBlitz здесь чтобы показать, как это может работать для отлова щелчка по элементам привязки.
Я добавил тело с изображением следующим образом:
<img src="x" onerror="alert(1)"></div>
чтобы показать, что дезинфицирующее средство выполняет свою работу.
Здесь, в этой скрипке, вы найдете то же тело, прикрепленное к
innerHTML
объекту без его дезинфекции, и это продемонстрирует проблему.источник