Loading...
事件系统能提供丰富的交互,在设计时我们遵循两个原则:
熟悉 DOM 事件流 的开发者对以下概念肯定不陌生:
下图展示了事件传播的三个阶段,在捕获阶段自顶向下依次触发监听器,到达目标节点后向上冒泡。在监听器中可以通过 eventPhase 获取当前所处的阶段。下图来自 https://javascript.info/bubbling-and-capturing#capturing
目前我们支持以下基础事件,尽可能兼容了 DOM 事件流,因此在下面的很多 API 介绍中我们都附上了 DOM Event API 对应的参考链接。
例如我们想给这个圆形增加简单的鼠标移入/移出的交互效果,示例
circle.addEventListener('mouseenter', () => {circle.attr('fill', '#2FC25B');});circle.addEventListener('mouseleave', () => {circle.attr('fill', '#1890FF');});
目前我们支持对于以下两类事件的监听:交互事件和场景图事件。前者和 DOM Event API 中提供的大部分鼠标、触屏事件相同,后者则是基于场景图在节点添加、删除、属性变换时触发。
浏览器对于交互事件的支持历经了以下阶段,详见:https://javascript.info/pointer-events#the-brief-history
下图来自:https://w3c.github.io/pointerevents/
于是如今 Level 2 的 PointerEvent 已经被所有主流浏览器支持:https://www.w3.org/TR/pointerevents2/
新的运行环境也都使用 PointerEvent 这样的统一定义,不再有 Touch / Mouse / PenEvent,例如:
因此我们推荐直接使用 PointerEvent。多指触控的手势也完全可以实现,例如:
目前支持监听如下交互事件:
Pointer 系列:
Mouse 系列:
Touch 系列:
除了交互事件,我们还可以监听一些场景图相关的事件,例如在画布上监听每一个节点的首次加载(g-svg 会在此时创建当前图形相关的 DOM),示例
import { ElementEvent } from '@antv/g';canvas.addEventListener(ElementEvent.MOUNTED, (e) => {e.target;});
目前我们支持如下场景图相关事件:
在下面的例子中,画布监听 INSERTED REMOVED MOUNTED 和 UNMOUNTED 事件。在加入、移除场景图时,以下事件会依次触发:
canvas.addEventListener(ElementEvent.INSERTED, (e) => {console.log(ElementEvent.INSERTED, e.target);});// 省略其他事件监听器parent.appendChild(child); // 构建父子关系canvas.appendChild(parent); // 加入场景图canvas.removeChild(parent, false); // 从场景图中移除,但不销毁// MOUNTED parent 父节点载入// MOUNTED child 子节点载入// INSERTED parent 父节点加入场景图// REMOVED parent 父节点被移除场景图// UNMOUNTED child 子节点卸载// UNMOUNTED parent 父节点卸载
为图形添加事件监听器,可以完全参考 DOM Event API:https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget/addEventListener
方法签名:
target.addEventListener(type, listener, options);target.addEventListener(type, listener, useCapture);
其中参数为:
Function
{ handleEvent: Function }
可选
boolean
,表示 listener 会在该类型的事件捕获阶段传播到该 EventTarget 时触发。boolean
,表示 listener 在添加之后最多只调用一次。如果是 true
, listener 会在其被调用之后自动移除。可选
boolean
默认为 false
。如果是 true
,向上冒泡的事件不会触发 listener。// 二者等价button.addEventListener('click', () => {});button.addEventListener('click', {handleEvent(e): {}});
注册仅在捕获阶段执行的监听器:
circle.addEventListener('click', () => {}, { capture: true });circle.addEventListener('click', () => {}, true);
注册仅执行一次的监听器:
circle.addEventListener('click', () => {}, { once: true });
为了兼容旧版 G API,也支持使用 on
,因此以下写法等价:
circle.addEventListener('mouseenter', () => {});circle.on('mouseenter', () => {});
关于监听器内 this 的指向问题可以参考该小节。
移除事件监听器
circle.removeEventListener('click', handler);
为了兼容旧版 G API,也支持使用 off
,因此以下写法等价:
circle.removeEventListener('mouseenter', () => {});circle.off('mouseenter', () => {});
移除所有事件监听器。
为了兼容旧版 G API,也支持使用 off
,因此以下写法等价:
circle.removeAllEventListeners();circle.off();
手动触发事件,和交互触发的事件一样会经历完整的事件传播流程。
https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent
⚠️ 在一个图形上手动触发事件前,必须保证该元素已经添加到画布上
除了内置标准事件,有时我们也需要触发一些自定义事件,参考 Web CustomEvent,我们也支持如下写法,示例:
import { CustomEvent } from '@antv/g';const event = new CustomEvent('build', { detail: { prop1: 'xx' } });circle.addEventListener('build', (e) => {e.target; // circlee.detail; // { prop1: 'xx' }});circle.dispatchEvent(event);
其中 CustomEvent 构造函数参数如下:
string
必填
选填
包含以下属性:
any
为了兼容旧版 G API,也支持使用 emit
:
circle.on('build', (e) => {e.target; // circlee.detail; // { prop1: 'xx' }});circle.emit('build', { prop1: 'xx' });