Angular2 中的事件委托

2023-12-24

我正在 ng2 中开发一个应用程序,但我正在努力解决一些问题。我正在构建一个日历,您可以在其中选择日期范围,我需要对此做出反应click & mouseenter/mouseleave日细胞上的事件。所以我有一个像这样的代码(简化的):

日历.组件.html

<month>
    <day *ngFor="let day of days" (click)="handleClick()" 
         (mouseenter)="handleMouseEnter()" 
         (mouseleave)="handleMouseLeave()" 
         [innerHTML]="day"></day>
</month>

但这在浏览器的内存中为我提供了数百个单独的事件侦听器(每天的单元格获得 3 个事件侦听器,并且我一次最多可以显示 12 个月,因此侦听器的数量将超过 1000 个)。

所以我想“以正确的方式”做到这一点,使用称为“事件委托”的方法。我的意思是,在父组件上附加一个单击事件(month),当它收到点击事件时,只需检查它是否发生在Day组件 - 只有这样我才会对这次点击做出反应。就像 jQuery 所做的那样on() 方法 http://api.jquery.com/on/当你通过它时selector范围。

但我是通过在处理程序代码中本地引用 DOM 元素来做到这一点的:

月份.组件.ts

private handleClick(event) {
    if (event.target.tagName === 'DAY') {
        // handle day click
    } else {
        // handle other cases
    }
}

我和我的同事拒绝了我的想法,因为 - 正如他们所说 - “在 NG2 中必须有一种更简单、正确的方法来处理这个问题;就像 jQuery 中一样。此外,它在这里失去了控制 - 你正在对 Day 的点击做出反应在月份的代码中。”

所以,我的问题是,有更好的方法吗?或者我是否正在尝试解决一个我不应该再费心解决的问题,因为用户的设备每天都会获得越来越多的内存/处理能力?

提前致谢!


Intro

我今天偶然发现了这一点,我确实可以在很多应用程序中看到这种实现的必要性。现在我不能保证这是 100% 最好的技术,但是我已经竭尽全力使这种方法尽可能地受到角度启发。

我提出的方法有两个阶段。第一阶段和第二阶段总共将增加years * months + years * months * days,所以一年内你将拥有12 + 365事件。


Stage Scope

Stage 1:将单击一个月时的事件委托到单击的实际日期,而不需要当天发生事件。
Stage 2:将所选日期传播回月份。

在深入研究之前,该应用程序由 3 个组件组成,这些组件按以下顺序嵌套:app => month => day


这就是所需的全部 html。 app.component 托管多个月份,month.component 托管多个天,而 day.component 不执行任何操作,只是将日期显示为文本。

应用程序组件.html

<app-month *ngFor="let month of months" [data-month]="month"></app-month>

月.component.html

<app-day *ngFor="let day of days" [data-day]="day">{{day}}</app-day>

day.component.html

<ng-content></ng-content>

这是相当标准的东西。


Stage 1

让我们来看看month.component.ts我们想要从哪里委托我们的活动。

// obtain a reference to the month(this) element 
constructor(private element: ElementRef) { }

// when this component is clicked...
@HostListener('click', ['$event'])
public onMonthClick(event) {
  // check to see whether the target element was a child or if it was in-fact this element
  if (event.target != this.element.nativeElement) {
    // if it was a child, then delegate our event to it.
    // this is a little bit of javascript trickery where we are going to dispatch a custom event named 'delegateclick' on the target.
    event.target.dispatchEvent(new CustomEvent('delegateEvent'));
  }
}

在阶段 1 和阶段 2 中,都有only1 个警告,即;如果您的子元素中嵌套了day.component.html,您需要为此实现冒泡,在 if 语句中实现更好的逻辑,或者快速破解......day.component.css :host *{pointer-events: none;}


Now we need to tell our day.component to be expecting our delegateEvent event. So in day.component.ts all you have to do (in the most angular way possible) is...
@HostListener('delegateEvent', ['$event'])
 public onEvent() {
   console.log("i've been clicked via a delegate!");
 }

这是有效的,因为 typescript 不关心事件是否是本机的,它只会将一个新的 javascript 事件绑定到元素,从而允许我们通过“本机”调用它event.target.dispatchEvent正如我们上面所做的month.component.ts.

第一阶段到此结束,我们现在成功地将每月的活动委托给每天的活动。


Stage 2

那么,如果我们说想要在委托事件中运行一点逻辑,会发生什么?day.component然后将其返回到month.component- 这样它就可以以非常面向对象的方法继续执行自己的功能?幸运的是,我们可以很容易地实现这一点!

In month.component.ts更新为以下内容。所发生的变化是,我们现在将通过事件调用传递一个函数,并定义回调函数。

@HostListener('click', ['$event'])
  public onMonthClick(event) {  
    if (event.target != this.element.nativeElement) {
      event.target.dispatchEvent(new CustomEvent('delegateEvent', { detail: this.eventDelegateCallback}));
    }
  }

  public eventDelegateCallback(data) {
    console.log(data);
  }

剩下的就是在内部调用这个函数day.component.ts...

public onEvent(event) {
    // run whatever logic you like, 
    //return whatever data you like to month.component
    event.detail(this.day);
}

不幸的是,我们的回调函数在这里的命名有点含糊,但是打字稿会抱怨该属性不是定义的对象文字CustomEventInit如果另有命名。


Multiple Event Funnel

这种方法的另一个很酷的事情是,您永远不必定义超过此数量的事件,因为您可以通过此委托汇集所有事件,然后在其中运行逻辑day.component.ts过滤依据event.type...

月份.组件.ts

@HostListener('click', ['$event'])
@HostListener('mouseover', ['$event'])
@HostListener('mouseout', ['$event'])
  public onMonthEvent(event) {  
    if (event.target != this.element.nativeElement) {
      event.target.dispatchEvent(new CustomEvent('delegateEvent', { detail: this.eventDelegateCallback }));
    }
  }

日组件.ts

private eventDelegateCallback: any;

@HostListener('delegateEvent', ['$event'])
  public onEvent(event) {
    this.eventDelegateCallback = event.detail;
    if(event.type == "click"){
       // run click stuff
       this.eventDelegateCallback(this.day)
    }
  }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Angular2 中的事件委托 的相关文章

  • 如何在 Angular 2 项目中使用 Bower 组件

    我是 Angular 2 的初学者 Angular 2 项目使用 npm 包 我们可以通过简单地导入来在 Angular 2 项目中使用它们 如下所示 import FormsModule from angular forms 另外 我们可
  • 如何在React-Native中选择ListView的一项?

    我是 React Native 的新手 我想使用 ListView 选择一项 当我第一次按下 item 时 ListView renderRow 被调用 但终究不起作用 我该如何修复这个错误 我的问题出在哪里 我写了一个演示here htt
  • 流媒体性能 - Canvas 与

    我正在开发一个应用程序 需要通过 webSocket 连接以每秒至少 30 帧的速度持续传输图像 我遇到了一些性能问题 并希望尽我所能进行优化 我想知道使用不断更新的图像之间的性能差异是什么 就像这样 img src someDynamic
  • Node.js Google-云存储上传目的地规范

    我有一个 Node js 服务器并且正在使用谷歌云上传一些图像文件的包Firebase 存储 上传本身工作正常 但 google cloud API 似乎只能将文件上传到 Firebase Storage 根文件夹 有没有办法指定远程位置来
  • 使用 Charts.js 禁用动画

    我在使用 Charts js 关闭动画时遇到一些问题 这是我的代码 var pieData value 30 color F38630 value 50 color E0E4CC value 100 color 69D2E7 var myP
  • 粉碎一个元素,向随机方向发送碎片

    我试图 粉碎 一个元素 例如 一个图像 并将其碎片朝随机方向飞行 当碎片到达目的地时 即x距离 以像素为单位 它们变成原始图像的较小版本 jQuery UI 的explode http api jqueryui com explode ef
  • Angular2 本地组件/模板重用

    我正在编写一些 Angular2 模板 这些模板具有不同容器的重复部分 在这种情况下 如果对事物进行分组并且启用了多部分模式 则视图可能会发生变化 请原谅这个很长的例子 但是像这样
  • 如何获得相对于特定父级的偏移量?

    我想获取元素相对于的偏移量特定的父母不是直接的 也不是文档 我在互联网上查找并找到了offset http api jquery com offset and position http api jquery com position jQ
  • 强制执行 show.bind

    我有一个包含数据的表 当从另一个视图触发事件时 我希望视图检查 show bind 语句 问题是该事件没有更改当前视图中的任何数据 foo html tr p canBeRemoved p tr 我正在使用 EventAggregator
  • 从对象获取数据 - 我看到数据但无法保存它们

    正如你所看到的 我是新来的 我确实尝试过搜索 但没有找到解决我问题的方法 所以这是我的问题 如果我这样做 console log grid data kendoGrid data 这在控制台中显示如下 所以我明白这一点 有一个数组和一个带有
  • 如何垂直打印数组中的字符串元素? [关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 我有一个数组 我想垂直打印每个元素 例如 myArr abc def ghi 输出应该是 a d g b e h c f
  • Facebook 登录无法在移动浏览器中使用

    我使用 react facebook login 在我的网站中实现了 facebook 登录module https github com keppelen react facebook login 我在 ComponentDidMount
  • jQuery 如何通过不同的列值计算表中的行数

    如何按表列计算不同的表行 Example table thead tr th NAME th th TECHNOLOGY th tr thead tbody tr td john td td jQuery td tr tr td mark
  • 谷歌浏览器如何启动桌面应用程序?

    我真的不知道术语 所以我将从一个例子开始 如果我点击磁力链接 Google Chrome 会询问我是否要启动 torrent 客户端 我单击 确定 chrome 启动该应用程序 该应用程序根据链接执行一些操作 现在有办法查看应用程序如何从
  • 单击时突出显示文本(javascript jquery html)

    当您在所有浏览器中双击某个单词时 它们会自动突出显示单击下的单词 但是否有可能找到一种方法exact单击一下就会发生同样的事情吗 我想这涉及到的事情可能是 TextRange 的东西 对所有段落 或整个正文或 div 的 onclick 做
  • 用于图形操作的 Javascript 库

    有没有建议的 javascript 替代 pythonpygraph http code google com p python graph or NetworkX http networkx lanl gov 应该注意的是 可视化不是必需
  • 按钮导致页面重新加载

    我在我的页面上使用 html 和 jquery 在我的 html 中 我有一个按钮 单击该按钮将触发一个功能 当页面加载时 我调用文档准备中的主函数 这是我的代码 div div
  • 正则表达式获取两个方括号之间的数字

    您好 我需要使用正则表达式在 JavaScript 中获取两对方括号内的字符串 这是我的字符串 12 23 asd 到目前为止我尝试的是使用这种模式 d 我需要获得价值12使用正则表达式 您可以使用以下正则表达式 d 这将提取12 from
  • 在 Sublime Text 下获取完整的 JS 自动补全

    我刚刚在 Windows Vista 下安装了 Sublime Text 甚至遵循了中给出的建议这个帖子 https stackoverflow com questions 10636410 modifying sublime text 2
  • 调试客户端时使用 Chrome/Firefox

    我正在使用带有 getUserMedia 的相机 但出现了一些需要修复的错误 问题是 Visual Studio 只允许我使用 IE 调试 JavaScript 我的意思是命中断点 而 IE 不支持 getUserMedia 如果您想在 I

随机推荐

  • WSO2 ESB 覆盖 ContentType 属性

    我正在开发 WSO2 ESB 代理服务 该服务涉及通过 ESB 上的 SOAP 端点公开内部 RESTful 服务 我的 RESTful 服务需要 Content type application rdf xml 我尝试使用文档中提到的所有
  • 如果函数创建并返回一个对象,它是否应该在自动释放池中

    我对 Objective C 还是很陌生 据我所知 任何我没有从 alloc new copy 或 mutableCopy 获得的对象都应该被假定在自动释放池中 我认为这也意味着 如果我创建一个创建并返回对象的新实例的函数 我应该在返回之前
  • 在lstm语言模型中使用预训练的word2vec?

    我用tensorflow来训练LSTM语言模型 代码来自here https github com tensorflow models blob master tutorials rnn ptb ptb word lm py 根据文章her
  • 将多个 json 数据添加到 panda 数据帧

    我正在使用 api 获取 3 个 json 数据 我想将这些数据添加到 1 个 panda 数据帧 这是我的代码 我传入的书籍中包含书籍 id 作为 x 这 3 个 id 返回了 3 个不同的 json 对象 其中包含所有书籍信息 for
  • WPF DataGrid CanUserAddRows = True

    我似乎在向 a 添加行时遇到问题DataGrid通过界面本身 这是用户界面的屏幕截图 正如您所看到的 在数据 库中找到了 0 行 因此没有任何内容显示在数据库中DataGrid在右侧 但我喜欢那里有一个空行 用于手动添加行 这DataGri
  • 获取 iOS Swift 中的顶级 ViewController

    我想实现一个单独的 ErrorHandler 类 它显示某些事件的错误消息 此类的行为应该从不同的其他类中调用 当发生错误时 会有一个UIAlertView作为输出 此 AlertView 的显示应始终位于顶部 因此 无论错误从哪里抛出 最
  • 如何将 RPC 与 Volttron 结合使用

    我想在我的 volttron 应用程序中使用 RPC 调用 但我无法让任何调用正常工作 所有调用都会失败 并出现 没有到主机的路由 错误
  • 为什么 Django 开发服务器会挂在这个管理工具 JS 文件上?

    使用 Django 管理工具时 它会定期挂起并停止响应请求 直到重新启动为止 每当它挂起时 日志中的最后一行是 获取 admin jsi18n HTTP 1 1 200 2158 挂起似乎发生在 POST 之后 例如查看添加对象的结果时 据
  • flowtype如何用可选字段注释联合

    如何在流程中实现以下目标 export type Response err string data Array data Array 我想表达一种类型 它返回错误和可选数据 或者不返回错误字段 如果没有 但是 我用它作为 return er
  • “npx tsc --version”报告虚拟机内不同的 TypeScript 版本

    我希望能够跑步npx tsc在我的主机 来宾操作系统上的项目中 但客人正在使用不同的 旧的 版本tsc 我不确定它是从哪里来的 我的设置 主机操作系统 Windows 10 来宾操作系统 Debian 9 我正在使用 VirtualBox
  • 使用 IDisposable 取消订阅事件

    我有一个处理来自 WinForms 控件的事件的类 根据用户正在执行的操作 我引用该类的一个实例并创建一个新实例来处理同一事件 我需要首先从事件中取消订阅旧实例 很简单 如果可能的话 我想以非专有的方式执行此操作 这似乎是 IDisposa
  • JQuery 自动完成:如何强制从列表中选择(键盘)

    我正在使用 JQuery UI 自动完成 一切都按预期进行 但是当我使用键盘上的向上 向下键循环时 我注意到文本框按预期填充了列表中的项目 但是当我到达列表末尾并再次按下向下箭头时这时 我输入的原始术语就会出现 这基本上允许用户提交该条目
  • git p4克隆/同步:如何添加新的P4路径

    我创建了一个 P4 客户端视图规范 并用它制作了一个 git p4 克隆 并定期同步 P4 的更改 效果非常好 有一天 我想向我克隆的 Git 存储库添加另一个 P4 路径 但它卡住了 即使我添加了 git p4 克隆使用的客户端视图规范的
  • mysql 自动终止查询

    mysql 是否有可能自动终止耗时超过 20 秒的查询 我猜您正在寻找名为 mk kill 的 maatkit 实用程序 它将杀死符合某些条件的查询
  • Tf.Print() 不打印张量的形状?

    我使用 Tensorflow 编写了一个简单的分类程序并获取输出 但我尝试打印模型参数 特征和偏差的张量形状 函数定义 import tensorflow as tf numpy as np from tensorflow examples
  • 我的解决方案中有两个 Web 项目,要部署哪一个

    我有一个像这样结构的解决方案 Proj Soln Proj Api csproj Proj Web csproj 我已使用 bitbucket org 配置了 microsoft azure 当我通过 git 提交到 bitbucket 时
  • Linux Mint 19.2 上的 Docker 安装不起作用 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 刚刚安装了一个新的 Linux mint 19 2 我需要 docker 所以我去了 docker 文档并遵循了该过程 https doc
  • 将值传递给捆绑的 React JS 文件?

    我想知道是否可以将参数传递给反应入口点 我的入口点如下所示 module exports entry js components Application js output path dist filename bundle js 我的应用
  • 如何在turbo c++ 16位编译器中创建项目

    我想创建一个项目文件 Turbo C 并链接该项目中的文件 虽然我已经尝试过 但我发现只有一个选项可以打开项目 没有选项可以创建新项目 那么如何做到这一点 基本上 你想做的是 开放项目 在那里 您输入项目名称 它必须以 PRJ 当你open
  • Angular2 中的事件委托

    我正在 ng2 中开发一个应用程序 但我正在努力解决一些问题 我正在构建一个日历 您可以在其中选择日期范围 我需要对此做出反应click mouseenter mouseleave日细胞上的事件 所以我有一个像这样的代码 简化的 日历 组件