简介
事件模块作为 VTable 中交互功能的入口模块,主要监听了两部分的事件:
-
外部事件的监听,场景树相关的事件。
-
原生 DOM 事件的监听。
本文将从上面两个角度进行分析,讲述 VTable 的事件具体监听了哪些事件。
监听收口
绝大部分的事件监听都是在 EventManager 模块中完成的,其中主要的收口位于 bindOuterEvent,接下来将通过该函数来剖析关于 VTable 中关于事件的监听部分。
// packages\vtable\src\event\event.ts
export class EventManager {
// ...
bindOuterEvent() {
bindTableGroupListener(this);
bindContainerDomListener(this);
bindScrollBarListener(this);
bindTouchListener(this);
bindGesture(this);
}
}
bindOuterEvent 分为五个部分:
-
bindTableGroupListener: 主要是监听外部事件,场景树相关事件;
-
bindContainerDomListener:监听原生DOM事件;
-
bindScrollBarListener:监听外部滚动条事件;
-
bindTouchListener:监听移动端触摸事件,内部会同时监听原生 DOM 和 外部事件;
-
bindGesture:监听双击事件,触发关于双击的自定义事件;
下面将详细对这几个模块进行分析。
DOM 相关事件
表格容器
bindContainerDomListener 内部负责监听原生 DOM 事件,主要是监听下面两个对象。
document 相关

表格容器

源码
- bindContainerDomListener
// vtable\src\event\listener\container-dom.ts // 容器级事件 handler.on(table.getElement(), 'blur', ...); // 失去焦点 handler.on(table.getElement(), 'keydown', ...); // 键盘事件(快捷键) handler.on(table.getElement(), 'copy', ...); // 复制操作 handler.on(table.getElement(), 'paste', ...); // 粘贴操作 handler.on(table.getElement(), 'contextmenu', ...); // 右键菜单 // 全局指针事件 document.body.addEventListener('pointerdown', ...); // 全局按下 document.addEventListener('pointerup', ...); // 全局释放 document.body.addEventListener('pointermove', ...); // 全局移动 // 容器尺寸变化 handler.on(table.getContainer(), 'resize', ...); // 容器resize
移动端事件
- bindTouchListener
bindTouchListener 监听的是移动端事件,主要是为了兼容移动端的表格移动功能。

- 源码
// packages\vtable\src\event\listener\touch.ts
window.addEventListener('touchmove', (e) => { // 触摸移动
// 1. 阻止默认滚动行为
// 2. 计算滑动距离(deltaX/deltaY)
// 3. 调用handleWhell实现表格内容滚动
});
window.addEventListener('touchend', (e) => { // 触摸结束
// 触发惯性滚动
});
window.addEventListener('touchcancel', (e) => {
// 清空移动端 touch 事件相关参数
});
场景树相关
场景树基础事件
场景树分为三个部分来进行监听,下面分别来进行讲解:
tableGroup
表格整体 Group 容器相关,主要是去监听于 VRender 提供的事件;

stage 事件

全局事件

源码
- bindTableGroupListener
// packages\vtable\src\event\listener\table-group.ts // 表格组基础事件 table.scenegraph.tableGroup.addEventListener('pointermove', ...); // 指针移动 table.scenegraph.tableGroup.addEventListener('pointerdown', ...); // 指针按下 table.scenegraph.tableGroup.addEventListener('pointerup', ...); // 指针释放 table.scenegraph.tableGroup.addEventListener('pointerover', ...); // 指针进入区域内部 table.scenegraph.tableGroup.addEventListener('pointerenter', ...); // 指针穿过区域边界 table.scenegraph.tableGroup.addEventListener('pointerleave', ...); // 指针离开区域 table.scenegraph.tableGroup.addEventListener('pointertap', ...); // 指针点击 table.scenegraph.tableGroup.addEventListener('rightdown', ...); // 右键点击 table.scenegraph.tableGroup.addEventListener('wheel', ...); // 滚轮事件 table.scenegraph.tableGroup.addEventListener('checkbox_state_change', ...); // 多选框状态改变 table.scenegraph.tableGroup.addEventListener('radio_checked', ...); // 单选框状态改变 // stage 相关 table.scenegraph.stage.addEventListener('pointerdown', ...); table.scenegraph.stage.addEventListener('pointerup', ...); table.scenegraph.stage.addEventListener('pointertap', ...); table.scenegraph.stage.addEventListener('pointermove', ...); // vglobal vglobal.addEventListener('pointerup', globalPointerupCallback); vglobal.addEventListener('pointerdown', globalPointerdownCallback);
滚动条相关事件
bindScrollBarListener 中监听了 VRender 的ScrollBar 组件提供的事件。
VTable 存在两种滚动条,分别是水平滚动条 hScrollBar ,垂直滚动条 vScrollBar 。这两种滚动条监听的事件类型都是相同的。以垂直滚动条为例,主要监听下面几个事件:
-
pointerover
-
pointerout
-
pointerup
-
pointermove
-
pointerupoutside
-
scrollDown
-
scrollDrag
-
scrollUp
bindScrollBarListener
// packages\vtable\src\event\listener\scroll-bar.ts // 垂直滚动条事件 scenegraph.component.vScrollBar.addEventListener('pointerover', (e) => { // 指针悬停 stateManager.showVerticalScrollBar(); // 显示滚动条 }); scenegraph.component.vScrollBar.addEventListener('pointerout', (e) => { // 鼠标移出 stateManager.hideVerticalScrollBar(); // 隐藏滚动条 }); scenegraph.component.vScrollBar.addEventListener('pointerdown', (e) => { // 鼠标按下 // 1. 阻止事件冒泡 // 2. 触发MOUSEDOWN_TABLE事件 }); // 滚动条拖动事件 scenegraph.component.vScrollBar.addEventListener('scrollDrag', ((e) => { // 1. 同步表格滚动位置 // 2. 更新画布渲染 })); scenegraph.component.vScrollBar.addEventListener('scrollDown', (e) => { // 点击滚动条,更新滚动状态 }); // 鼠标从滚动条上抬起事件,清除滚动状态 scenegraph.component.vScrollBar.addEventListener('scrollUp', (e:) => {})
移动端事件
bindTouchListener 中单独为 tableGroup 注册了一份 touchstart 的回调,用来初始化移动端 touch 的信息。
// packages\vtable\src\event\listener\touch.ts // 基础触摸事件 table.scenegraph.tableGroup.addEventListener('touchstart', (e: FederatedPointerEvent) => { // 记录触摸点坐标和时间戳 eventManager.touchMovePoints.push({...}); });
结语
VTable 有着十分复杂的交互系统,而实现这些交互依赖的最重要的一个模块就是事件模块,在事件模块中,监听了几十种事件,包括了自定义事件和外部事件。
正是因为 VTable 有着如此健全的事件监听功能,才能实现这么多丝滑的交互。
本文档由以下人员提供
taiiiyang(https://github.com/taiiiyang)