Airglass.js开发笔记:监听

全篇共 1940 字。按500字/分钟阅读,预计用时 3.9 分钟。页面总浏览量 12 次,今日浏览量 1 次。

Airglass要做的是FUI/HUD风格的UI基础组件库,自然少不了对UI交互功能的支持。我利用事件委托,将canvas监听到的事件派发给canvas中绘制的虚拟元素。我甚至让开发者能够订阅虚拟元素触发的各种定制化事件,例如创建和移除事件等。据此实现用户操作画布中虚拟UI的可能。

继承性

在起步走那一篇想法中,我在最后提到Airglass.js中类的定义以及如何梳理类之间继承关系这件事。对此,我借鉴了Three.js的一些概念,比如关于场景和渲染器的概念,并将这些概念加入到我的Airglass.js中。我也定义了Scene类和Renderer类。Scene类用于维护场景中放置的所有物体。Renderer类用来渲染场景中的物体。

Airglass.js中的类与类之间的继承关系

场景需要具备增加和移除物体的能力,但场景类的特性却不止于此。我将Scene类继承Group类,Group实现添加和移除元素的能力。我之所以创建Group类,是因为也许还会有需要继承Group特性的类。顾名思义,渲染器类是用来控制如何将场景中的物体显示到屏幕上的类。我甚至赋予渲染器充当委托人的角色,因为我将canvas元素交给渲染器来维护。渲染器知道将哪一个场景渲染到哪一个画布上。说明可以有不止一个画布,说是我为了提升渲染性能做的尝试,我让一些渲染器维护那些需要频繁渲染其中内容的画布,而一些不常改变的画布交给另一些渲染器维护。

我曾创建一个继承Shape类,名为DraggableShape的类。经过一些反复琢磨的时候,我发现这样做只会增加继承关系的复杂度。这也提醒了我:在享受继承带来的便利时,也要看到继承背后的黑洞。就像我在设计Point类和Line类清醒地认识到:Point和Line并没有继承关系,而Line的实例需要两个Point实例才能表示一条线。

有些类从它起到的作用来看就很抽象,比如我定义了Element类,我称它为无形。Shape继承了Element,我称它为有形,有形之物生于无形之中。

我曾试着将可交互的物体与不可交互的物体分开。后来我发现,这同样会掉入继承的黑洞。不过是另一种黑洞:重复创建成员属性和方法。所以我知道了,如果一旦发现这两种继承黑洞,是时候考虑去掉一层继承关系了。

虚拟事件

什么事虚拟事件。在DOM的世界里,给DOM元素添加鼠标、键盘、触摸等事件监听器很容易。在Canvas画布的小小又大大的世界里,如何给许多个圆形添加这些事件呢。我受为列表项添加事件委托的启发。将canvas画布中的元素各种与鼠标、键盘、触摸等事件交互的行为委托给canvas画布处理。当canvas画布接收到外部交互行为时,它将触发监听在虚拟元素上的虚拟事件。

canvas中虚拟元素拖拽操作

当我像游戏规则的制定者一般,考虑着和如何安排DOM树的事件捕获与冒泡顺序一样的事,这时我才发现事情其实并不简单,思路却如此清晰。就像已经非常熟悉潜水的人对于翻船这件普通人看似严重的事就像擅长竞走的人处理小石子绊了脚一样可以如此轻描淡写。

当canvas画布中的每一个虚拟元素感知到发生在它们身上的各种事件后,最终应该如何触发事件处理器呢。即使是被覆盖在下面的虚拟元素也能够感知到鼠标穿过了自己。有些处理应该交给开发者来决定。就像addEventListener的第三个参数的影响由开发者决定一样。我只需给出一个默认行为,而开发者可以覆盖这一默认行为定义他希望的虚拟元素的行为模式。

鼠标穿过各个虚拟元素捕获到的事件

交互与否

在继承性里我提到,利用多个渲染器维护多个canvas画布。一些画布作为事件委托人,即时将感知到的交互事件派发给开启了交互模式的元素。事实上,我希望中的FUI/HUD风格的UI组件也包括那些纯作为效果呈现而存在的组件。

数据驱动UI组件状态的更新和画布的渲染,就是我说的一种非用户触发的使UI改变的事件。所以我为虚拟元素和渲染器都增加了是否启用交互模式的切换方式。类似事件可以的订阅,可以退订。我将交互模式的启用与关闭设计的非常灵便。开发者甚至可以重新创建符合模式需要的虚拟元素和渲染器,这也是我非常推荐的手段。

Airglass.js 开发笔记系列想法:

发布日期 » 2019年9月8日 周日
原创声明 » 请勿复制转载,谢谢配合。
Airglass.js核心库
JavaScript核心概念
硬件编程、Arduino
文档翻译计划
微信开发
前端脚手架
运维
可视化
生活自有“道”理
视觉设计、用户体验
陈帅华的微信二维码