cocosCreator 之 dispatchEvent事件分发

news2024/9/25 21:25:00

版本: 3.8.0

语言: TypeScript

环境: Mac


Node事件派发


cocosCreator支持使用Node节点进行事件派发(dispatchEvent),事件派发系统是按照 Web 的事件冒泡及捕获标准 实现的。

事件派发主要通过冒泡的方式逐渐向父节点传递。

bubble-event

在派发后,会经历如下阶段:

  • 捕获:事件从场景根节点,逐级向子节点传递,直到到达目标节点或者在某个节点的响应函数中中断事件传递
  • 目标:事件在目标节点上触发
  • 冒泡:事件由目标节点,逐级向父节点冒泡传递,直到到达根节点或者在某个节点的响应函数中中断事件传递

实现的主要接口在Node的基类BaseNode中,主要有:

export class BaseNode extends CCObject implements ISchedulable {
  // 在节点上注册指定类型的回调函数,也可以设置 target 用于绑定响应函数的 this 对象
  on(type: string | __private.cocos_core_scene_graph_node_event_NodeEventType, callback: __private.AnyFunction, target?: unknown, useCapture?: any): void;
  // 删除之前与同类型,回调,目标或 useCapture 注册的回调
  off(type: string, callback?: __private.AnyFunction, target?: unknown, useCapture?: any): void;
  // 注册节点的特定事件类型回调,回调会在第一时间被触发后删除自身
  once(type: string, callback: __private.AnyFunction, target?: unknown, useCapture?: any): void;
  // 通过事件名发送自定义事件, 支持最多5个参数的传递
  emit(type: string, arg0?: any, arg1?: any, arg2?: any, arg3?: any, arg4?: any): void;
  // 分发事件到事件流中
  dispatchEvent(event: Event): void;
  // 检查事件目标对象是否有为特定类型的事件注册的回调
  hasEventListener(type: string, callback?: __private.AnyFunction, target?: unknown): any;
  // 移除目标上的所有注册事件
  targetOff(target: string | unknown): void;   
}

使用dispatchEvent进行事件分发,需要Event对象的支持,它是所有事件对象的基类,主要定义有:

export class Event {
  static NO_TYPE: string;				// 没有类型的事件
  static TOUCH: string;					// 触摸事件类型
  static MOUSE: string;					// 鼠标事件类型
  static KEYBOARD: string;			// 键盘事件类型
  static ACCELERATION: string;	// 加速器事件类型
  
  static NONE: number;						// 尚未派发事件阶段
  static CAPTURING_PHASE: number;	// 捕获阶段
  static AT_TARGET: number;				// 目标阶段
  static BUBBLING_PHASE: number;	// 冒泡阶段
  
  bubbles: boolean;			// 事件是否冒泡
  target: any;					// 最初事件触发的目标
  currentTarget: any;		// 当前目标
  
  // 事件阶段,主要用于返回NONE,CAPTURING_PHASE,AT_TARGET,BUBBLING_PHASE等
  eventPhase: number;
  // 停止传递当前事件
  propagationStopped: boolean;
  // 立即停止当前事件的传递,事件甚至不会被分派到所连接的当前目标
  propagationImmediateStopped: boolean;
  
  // 检查该事件是否已经停止传递
  isStopped(): boolean;
  // 获取当前目标节点
  getCurrentTarget(): any;
  // 获取事件类型
  getType(): __private.cocos_input_types_event_enum_SystemEventTypeUnion;
}

以上图为例,假设事件从节点c派发事件,节点a和b都收到事件的监听,可以这样编写示例:

// common.ts
class MyEvent extends Event {
    constructor(name: string, bubbles?: boolean, detail?: any) {
        super(name, bubbles);
        this.detail = detail;
    }
    public detail: any = null;  // 自定义的属性
}

// c.ts
import { Event } from 'cc';

public demo() {
  this.node.dispatchEvent( new MyEvent('foobar', true, 'detail info') );
}

// b.ts
this.node.on('foobar', (event: MyEvent) => {
  // 设置是否停止传递当前事件,如果为true,则a不再收到监听事件相关
  event.propagationStopped = true;
});

// a.ts
this.node.on('foobar', (event: MyEvent) => {
  //
});

如上内容,从官方文档: 节点事件系统 移植而来,主要用于对后面的自定义事件派发进行铺垫。


自定义事件派发


使用Node节点的冒泡派发,如果组件节点过多,可能会存在不够灵活和高效的问题。

事件分发的大概原理是:

  • 通过dispatchEvent将事件相关注册到一个事件表中
  • 通过addEventListener 根据事件类型检测事件表中是否存在,如果存在则执行
  • 通过removeEventListener根据事件类型将事件相关从表中移除,如果存在则移除

因此可封装一个简单的事件管理类: EventManager,大致实现:

import { error, _decorator } from "cc";
const { ccclass } = _decorator;

@ccclass("EventManager")
export class EventManager {
  static handlers: { [name: string]: { handler: Function, target: any }[] };
  // 添加监听(事件类型名,回调,目标节点)
  public static addEventListener(name: string, handler: Function, target?: any) {
    const objHandler = {handler: handler, target: target};
    if (this.handlers === undefined) {
      this.handlers = {};
    }
    let handlerList = this.handlers[name];
    if (!handlerList) {
      handlerList = [];
      this.handlers[name] = handlerList;
    }

    for (var i = 0; i < handlerList.length; i++) {
      if (!handlerList[i]) {
        handlerList[i] = objHandler;
        return i;
      }
    }

    handlerList.push(objHandler);

    return handlerList.length;
  };
  // 移除监听(事件类型名,回调,目标节点)
  public static removeEventListener(name: string, handler: Function, target?: any) {
    const handlerList = this.handlers[name];
    if (!handlerList) {
      return;
    }

    for (let i = 0; i < handlerList.length; i++) {
      const oldObj = handlerList[i];
      if (oldObj.handler === handler && (!target || target === oldObj.target)) {
        handlerList.splice(i, 1);
        break;
      }
    }
  };
  // 事件分发(事件类型名,自定义参数)
  public static dispatchEvent(name: string, ...args: any) {
    const handlerList = this.handlers[name];

    const params = [];
    let i;
    for (i = 1; i < arguments.length; i++) {
      params.push(arguments[i]);
    }

    if (!handlerList) {
      return;
    }

    for (i = 0; i < handlerList.length; i++) {
      const objHandler = handlerList[i];
      if (objHandler.handler) {
        objHandler.handler.apply(objHandler.target, args);
      }
    }
  };
};

使用示例:

// demoLayer.ts
import { EventManager } from '../EventManager';
export class demoLayer extends Component {
  protected onEnable(): void {
    EventManager.on("DEBUG_CUSTOM", this.customEvent, this);
  }

  protected onDisable(): void {
    EventManager.off("DEBUG_CUSTOM", this.customEvent, this);
  }
  
  private customEvent(param) {
    console.log(param);
  }
}

// gameManager.ts
EventManager.dispatchEvent("DEBUG_CUSTOM", 1);

理解可能有误,欢迎指出;最后祝大家学习生活愉快!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1130908.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

整数智能·迪拜GITEX 2023 |探索未来科技,感受创新脉搏

第43届GITEX GLOBAL在迪拜世界贸易中心盛大开幕&#xff0c;聚集来自全球各地的6000多家参展企业&#xff0c;包含大量来自于人工智能、区块链、网络安全、可持续技术等领域的科技巨头和革命性初创企业&#xff0c;展示全球科技最新趋势和创新机遇。GITEX GLOBAL始办于1981年&a…

OpenText 安全取证软件——降低成本和风险的同时,简化电子取证流程

OpenText 安全取证软件&#xff0c;行业标准的数字调查解决方案&#xff0c;适用于各种规模和各种行业的组织 降低成本和复杂性 • 远程调查比轮流调查过程更有效 对结果持有信心 • 磁盘级可见性可以完成相关端点数据的搜索和收集 谨慎调查 • 完整的网络调查&#xf…

Linux常用文件和目录管理

本文旨在对y总的Linux基础课做学习记录&#xff0c;方便日后复习 参考视频&#xff1a;Linux基础课 参考教程&#xff1a;Linux教程 0 绝对路径和相对路径 Linux 的目录结构为树状结构 绝对路径&#xff1a;由根目录 / 写起&#xff0c;例如&#xff1a; /usr/share/doc相对…

华为云2023年双十一服务器优惠价格表及活动大全

2023华为云双11优惠活动「云上优选 特惠来袭」&#xff0c;阿腾云atengyun.com整理云服务器优惠价格表&#xff0c;华为云L实例-2核2G3M一年优惠价89元、L实例-2核2G4M价格108元一年、L实例-2核4G5M优惠价198元一年&#xff0c;三年1000元、HECS云服务器-1核2G1M带宽39元一年、…

【C++】继承和多态

继承和多态 一、继承1. 继承概念2. 继承定义&#xff08;1&#xff09;继承的格式定义&#xff08;2&#xff09;继承父类成员访问方式的变化 3. 父类和子类对象赋值转换4. 继承中的作用域5. 子类的默认成员函数6. 继承与友元7. 继承与静态成员8. 复杂的菱形继承及菱形虚拟继承…

Zynq UltraScale+ XCZU9EG 纯VHDL解码 IMX214 MIPI 视频,2路视频拼接输出,提供vivado工程源码和技术支持

目录 1、前言免责声明 2、我这里已有的 MIPI 编解码方案3、本 MIPI CSI2 模块性能及其优越性4、详细设计方案设计原理框图IMX214 摄像头及其配置D-PHY 模块CSI-2-RX 模块Bayer转RGB模块伽马矫正模块VDMA图像缓存Video Scaler 图像缓存DP 输出 5、vivado工程详解PL端FPGA硬件设计…

linux安装nginx 1.25.2

1.下载nginx-1.25.2.tar.gz放在/opt下 wget http://nginx.org/download/nginx-1.25.2.tar.gz 2.解包 Nginx 软件包&#xff1a; tar -xvf nginx-1.25.2.tar.gz 3.安装 Nginx 依赖&#xff1a; 在安装 Nginx 之前&#xff0c;需要先安装一些依赖库&#xff1a;pcre、openss…

某大型车企:加强汽车应用安全防护,开创智能网联汽车新篇章

​某车企是安徽省最大的整车制造企业&#xff0c;致力于为全球消费者带来高品质汽车产品和服务体验&#xff0c;是国内最早突破百万销量的汽车自主品牌。该车企利用数字技术推动供应链网络的新型互动&#xff0c;加快数字化转型&#xff0c;持续进行场景创新、生态创新&#xf…

无线测温产品在菲律宾某工厂配电项目的应用

摘要&#xff1a;配电系统是由多种配电设备和配电设施所组成的变换电压和直接向终端用户分配电能的一个电力网络系统。由于配电系统作为电力系统的一个环节直接面向终端用户&#xff0c;它的完善与否直接关系着广大用户的用电可靠性和用电质量&#xff0c;因而在电力系统中具有…

总结使用React做过的一些优化

一、修改css模拟v-show {!flag && <MyComponent style{{display: none}} />} {flag && <MyComponent />}<MyComponent style{{ display: flag ? block : none }} />二、循环使用key const todosList todos.map(item > {<li key{it…

分享:身份证读卡器java工程乱码解决办法

身份证读卡器java工程乱码解决办法 1、窗口>首选项>常规>工作空间 文本文件编码选择&#xff1a;缺省值&#xff08;GBK&#xff09; 2、工程>属性>资源 文本文件编码选择&#xff1a;从容器继承&#xff08;GBK&#xff09; IDE for Eclipse Committers (in…

MES生产管理系统与供应链协同管理

MES生产管理系统在制造业中发挥着越来越重要的作用&#xff0c;它与供应链管理密切相关&#xff0c;对于提高供应链的协同和优化有着重要的意义。本文将探讨MES管理系统与供应链管理之间的关系&#xff0c;包括实时数据共享、生产计划协调和供应链效率提升等方面。 MES系统能够…

npm install 报node-sass command failed

一、前言 最近在前端项目Vue项目install时会出现node-sass command failed的错误&#xff0c;原因是NodeJS和node-sass的版本不对应导致的&#xff0c;本文将给出解决方案。 二、解决方案 以下是NodeJS和node-sass版本的对照关系&#xff1a;

彩虹知识商城7.0.3小森升级版新增供货商开心学习版

彩虹知识商城7.0.3小森升级版新增供货商开心学习版 1.新增邮件提醒功能&#xff0c;支持给用户发订单、结算等邮件通知 2.支持给管理员发送提现、域名审核等邮件通知 3.支持设置手续费最低扣除金额 4.修复了其他一些已知问题

QT 自定义窗体加载完成函数

使用信号和槽函数&#xff0c;具体如下&#xff1a; QT-如何在窗口/对话框显示后自动执行指定任务_qt 界面显示完在调用函数-CSDN博客文章目录QT-如何在窗口/对话框显示后自动执行指定任务一、如何实现在窗口展示出来后&#xff0c;执行某个函数二、如何成功实现判断条件后选择…

怒刷LeetCode的第28天(Java版)

目录 第一题 题目来源 题目内容 解决方法 方法一&#xff1a;动态规划 方法二&#xff1a;迭代 方法三&#xff1a;斐波那契数列公式 第二题 题目来源 题目内容 解决方法 方法一&#xff1a;栈 方法二&#xff1a;路径处理类 方法三&#xff1a;正则表达式 方法…

生活废品回收系统 JAVA语言设计和实现

目录 一、系统介绍 二、系统下载 三、系统截图 一、系统介绍 基于VueSpringBootMySQL的生活废品回收系统包含资源类型模块、资源品类模块、回收机构模块、回收机构模块、资源销售单模块、资源交易单模块、资源交易单模块&#xff0c;还包含系统自带的用户管理、部门管理、角…

QGIS003:【04地图导航工具栏】-地图显示、新建视图、时态控制、空间书签操作

摘要&#xff1a;QGIS地图导航工具栏包括平移地图、居中显示、放大、缩小、全图显示、缩放到选中要素、缩放到图层、缩放到原始分辨率、上一视图、下一视图、新建地图视图、新建3D地图视图、新建空间书签、打开空间书签、时态控制面板、刷新等选项&#xff0c;本文介绍各选项的…

Linux软件包和进程管理

一、RPM软件包管理 1、RPM管理工具 &#xff08;1&#xff09;RPM是红帽包管理(Redhat Package Manager)的缩写。 由Red Hat公司提出的一种软件包管理标准。 是Linux各发行版中应用最广泛的软件包格式之一&#xff08;还有debian的发行版deb安装包&#xff09;。 RPM功能通过…

借助文心大模型4.0轻松搞定统计报表

在10月17日的百度世界2023上&#xff0c;文心大模型4.0版本正式发布&#xff01;会上百度董事长李彦宏为我们展示了文心大模型4.0在多轮对话、搜索、地图、商业智能、智能会议、智能视频等方面的强悍。 对此我们保持疑问&#xff0c;那文心大模型4.0真有这么好&#xff1f;我们…