!!!###!!!title=4.2 事件监听——VisActor/VTable 社区贡献者文档!!!###!!!!!!###!!!description=---title: 4.2 事件监听 key words: VisActor,VChart,VTable,VStrory,VMind,VGrammar,VRender,Visualization,Chart,Data,Table,Graph,Gis,LLM--- !!!###!!!

简介

事件模块作为 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)

本文档由以下人员修正整理

玄魂