角度2如何保持事件触发摘要循环? [英] Angular 2 how to keep event from triggering digest loop?

查看:97
本文介绍了角度2如何保持事件触发摘要循环?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在使用Angular 2实现拖放功能。



我正在使用 dragover 事件运行 preventDefault()函数。因此, drop 事件的作用与此问题中所述的一样。



dragover 方法由 onDragOver 功能在组件中。

 < div draggable =true
(dragover)=onDragOver($ event)>
...

在组件中,此功能可以防止拖动项目的默认行为被放在这个目标上。

  onDragOver(event){
event.preventDefault();
}

这样可以预期。 dragover事件每几毫秒触发一次。



但是,每次调用 onDragOver 函数时,Angular 2将运行其摘要循环。这会减慢应用程序的速度。我想运行这个功能而不触发摘要循环。



我们使用的解决方法是订阅元素事件,并将其运行在Angular 2的上下文之外,如下所示:

 构造函数(ele:ElementRef,private ngZone:NgZone){
this.ngZone.runOutsideAngular(()=> {
Observable.fromEvent nativeElement,dragover)
.subscribe((event:Event)=> {
event.preventDefault();
}
);
});
}

这工作正常。但是有没有办法实现这一点,而不必直接访问nativeElement?

解决方案

1)一个有趣的解决方案可能是覆盖 EventManager



custom-event-manager.ts

  import {Injectable,Inject,NgZone};来自'@ angular / platform-b​​rowser'的
import {EVENT_MANAGER_PLUGINS,EventManager};

@Injectable()
导出类CustomEventManager扩展EventManager {
构造函数(@Inject(EVENT_MANAGER_PLUGINS)插件:any [],私人区域:NgZone){
super (插件,区域);
}

addEventListener(element:HTMLElement,eventName:string,handler:Function):Function {
if(eventName.endsWith('out-zone')){
eventName = eventName.split('。')[0];
return this.zone.runOutsideAngular(()=>
super.addEventListener(element,eventName,handler));
}

return super.addEventListener(element,eventName,handler);
}
}

app.module.ts

  ... 
providers:[
{provide:EventManager ,useClass:CustomEventManager}
]
})
导出类AppModule {

用法:

 < h1(click.out-zone)=test )>点击ng区域外的< / h1> 

< div(dragover.out-zone)=onDragOver($ event)>

Plunker示例



所以使用上面的解决方案,您可以使用这些选项之一来防止默认行为并在角区域之外运行事件:

 (dragover.out-zone)=$ event.preventDefault() 
(dragover.out-zone)=false
(dragover.out-zone)=!! 0

2) Rob Wormald提供的另一个解决方案是使用Zonejs的黑名单



blacklist.ts

  const BLACKLISTED_ZONE_EVENTS:string [] = [
'addEventListener:mouseenter',
'addEventListener:mouseleave',
'addEventListener:mousemove',
'addEventListener:mouseout ,
的addEventListener:鼠标悬停,
的addEventListener:滚轮,
的addEventListener:滚动,
requestAnimationFrame,
];

export const blacklistZone = Zone.current.fork({
name:'blacklist',
onScheduleTask:(delegate:ZoneDelegate,current:Zone,target:Zone,
task:Task):Task => {

//黑名单滚动,鼠标和请求动画帧事件
if(task.type ==='eventTask'& &
BLACKLISTED_ZONE_EVENTS.some(
(name)=> task.source.indexOf(name)> -1)){
task.cancelScheduleRequest();

//在根区域中调度任务,注意Zone.root!= target,
//target区域是Angular。在Zone.root内调度任务将
//阻止无限摘要
return Zone.root.scheduleTask(task);
} else {
return delegate.scheduleTask(target,task);
}
}
});

main.ts


$ b $

黑名单Zone.run(()=> {
platformBrowser()。bootstrapModuleFactory(...)
})


We are implementing drag and drop functionality with Angular 2.

I'm using the dragover event just to run the preventDefault() function. So that the drop event works as explained in this question.

The dragover method is being handled by the onDragOver function in the component.

<div draggable="true"
    (dragover)="onDragOver($event)">
...

In the component, this function prevents default behavior allowing for the dragged item to be dropped at this target.

onDragOver(event) {
    event.preventDefault();
}

This works as expected. The dragover event gets fired every few hundred milliseconds.

But, every time the onDragOver function is called, Angular 2 runs its digest cycle. This slows down the application. I'd like to run this function without triggering the digest cycle.

A workaround we use for this is subscribing to element event and running it outside of the Angular 2's context as follows:

constructor( ele: ElementRef, private ngZone: NgZone ) {
    this.ngZone.runOutsideAngular( () => {
        Observable.fromEvent(ele.nativeElement, "dragover")
            .subscribe( (event: Event) => {
                event.preventDefault();
            }
        );
    });
}

This works fine. But is there a way to achieve this without having to access the nativeElement directly?

解决方案

1) One interesting solution might be overriding EventManager

custom-event-manager.ts

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

@Injectable()
export class CustomEventManager extends EventManager {
  constructor(@Inject(EVENT_MANAGER_PLUGINS) plugins: any[], private zone: NgZone) {
    super(plugins, zone); 
  }

  addEventListener(element: HTMLElement, eventName: string, handler: Function): Function {
    if(eventName.endsWith('out-zone')) {
      eventName = eventName.split('.')[0];
      return this.zone.runOutsideAngular(() => 
          super.addEventListener(element, eventName, handler));
    } 

    return super.addEventListener(element, eventName, handler);
  }
}

app.module.ts

  ...
  providers: [
    { provide: EventManager, useClass: CustomEventManager }
  ]
})
export class AppModule {

Usage:

<h1 (click.out-zone)="test()">Click outside ng zone</h1>

<div (dragover.out-zone)="onDragOver($event)">

Plunker Example

So with solution above you can use one of these options to prevent default behavior and run event outside angular zone:

(dragover.out-zone)="$event.preventDefault()"
(dragover.out-zone)="false"
(dragover.out-zone)="!!0"

2) One more solution provided by Rob Wormald is using blacklist for Zonejs

blacklist.ts

const BLACKLISTED_ZONE_EVENTS: string[] = [
  'addEventListener:mouseenter',
  'addEventListener:mouseleave',
  'addEventListener:mousemove',
  'addEventListener:mouseout',
  'addEventListener:mouseover',
  'addEventListener:mousewheel',
  'addEventListener:scroll',
  'requestAnimationFrame',
];

export const blacklistZone = Zone.current.fork({
  name: 'blacklist',
  onScheduleTask: (delegate: ZoneDelegate, current: Zone, target: Zone,
                   task: Task): Task => {

    // Blacklist scroll, mouse, and request animation frame events.
    if (task.type === 'eventTask' &&
        BLACKLISTED_ZONE_EVENTS.some(
            (name) => task.source.indexOf(name) > -1)) {
      task.cancelScheduleRequest();

      // Schedule task in root zone, note Zone.root != target,
      // "target" Zone is Angular. Scheduling a task within Zone.root will
      // prevent the infinite digest cycle from appearing.
      return Zone.root.scheduleTask(task);
    } else {
      return delegate.scheduleTask(target, task);
    }
  }
});

main.ts

import {blacklistZone} from './blacklist'

blacklistZone.run(() => {
  platformBrowser().bootstrapModuleFactory(...)
})

这篇关于角度2如何保持事件触发摘要循环?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆