D3 事件分发模块
参考
- d3-dispatch - 代码库
- d3-dispatch - 说明文档
- Observable Plot 官方样例 Focus + context II - 基于 d3-dispatch 模块实现两个可视化图的数据同步
本文主要介绍 d3-dispatch 模块 它是一个较为底层的模块,用于实现事件驱动的交互。在很多与交互相关的 D3 模块中(例如 d3-drag 模块),会使用该模块所提供的事件分发器来 dispatch 分发自定义事件,以触发预设的响应函数
使用 d3.dispatch(...types)
方法创建一个事件分发器(在下文简称为 dispatch 事件分发器),其中剩余参数 ...types
是一系列的字符串,表示自定义的事件类型(的名称)
// 创建一个事件分发器
// 它可以分发两种类型的自定义事件:"start" 事件 和 "end" 事件
const dispatch = d3.dispatch("start", "end");
还可以通过调用原有的事件分发器的方法 dispatch.copy()
生成一个拷贝(可以分发和监听相同类型的自定义事件),但是对于这个新的事件分发器的更改(例如在它上面设置的监听器),并不影响原有的分发器(反之亦然)
提示
以下是 DOM 原生的 EventTarget
的介绍
The EventTarget interface is implemented by objects that can receive events and may have listeners for them. In other words, any target of events implements the three methods associated with this interface.
EventTarget 接口是有一个对象实现的,在它上面可以注册监听器,以接收事件(并作出响应,执行预设的回调函数)
可以将事件分发器 dispatch 视作 EventTarget
,因为事件分发器可以为自定义事件创建监听器,在接收到相应类型的事件时,会执行相应的回调函数
不同的是,通过 dispatch 所设置的监听器可以是具名的(即可以为它们设置名称),以便进行移除或替换(相应的回调函数)
事件分发器当然也可以分发自定义的事件
以上方法返回一个事件分发器 dispatch,它是一个对象,具有一些方法:
dispatch.on(typenames, callback)
为给定类型的事件typename
创建或删除监听器
参数typenames
是字符串,表示自定义事件类型,例如start
事件。在事件类型后面可以额外添加字符串作为该监视器的名字,并以.
作为分隔符,例如start.foo
,这样所创建的监听器就是具名的,以便进行移除或替换(相应的回调函数)。也可以同时设置多个具名监听器(它们用空格" "
分隔),例如该参数的值为start.foo start.bar
;甚至可以同时为不同类型的事件设置监听器,例如该参数的值为start end
(这些监听器都执行相同的处理步骤,因为它们的回调函数相同)具名监听器
具名监听器虽然并不改变它所侦听的事件类型(在分隔符
.
前面所指定的才是事件类型),但如果将回调函数与监听器的名称相绑定对应,便于后续进行更精细、更灵活的管理和控制:- 可以为同一种类型的事件设置多个具名监听器,然后将响应步骤进行细分,分散写入到这些具名监听器的回调函数中。当这些监听器接收到相应类型的事件时,它们所预设的回调函数都会执行
- 然后根据具体的场景可以按需删除一些具名监听器事件,以取消执行相应的回调函数,而其他保留的具名监听器的回调函数依然可以执行
参数callback
是所需注册的回调函数。如果没有设置该参数,(而且给定类型的事件typenames
已经注册有回调函数)则该方法最终返回已设置的回调函数(若typenames
包含多个名称,则依序寻找这些监听器已经注册的回调函数,并返回首个找到的回调函数);如果该参数设置为null
则删除该监听器,例如移除所有名称为foo
的监听器,可以使用方法dispatch.on('.foo', null)
;如果typenames
所对应的监听器已经注册有回调函数,则会先将原有的回到函数移除,再注册给定的回调函数dispatch.call(type, that, ...arguments)
与dispatch.apply(type, that, arguments)
分发类型为type
的事件
参数type
是字符串,表示所需分发的事件类型
参数that
是一个对象,用于修改响应事件的回调函数中this
的指向,以便提供合适的上下文回调函数的 this
函数中的
this
与调用该函数的上下文相关方法
dispatch.call()
和dispatch.apply()
可以通过第二个参数对事件的回调函数的this
进行修改如果自定义事件与原生的 DOM 事件相关联,例如在原生的 DOM 事件里再使用上述任一方法分发自定义事件,则可以将原生事件的
this
(监听器所关联/绑定的 DOM 元素,即事件对象属性event.currentTarget
的值 )作为第二个参数,这样就可以将原生事件回调函数的上下文传递给自定义事件的回调函数中jsselection.on("click", function() { dispatch.apply("custom", this, arguments); });
方法dispatch.call(type, that, ...arguments)
设置剩余参数...arguments
,所以该方法可以接收任意数量的参数,从第三个参数开始(包含第三个参数),后面的参数都会封装为一个数组,并传递给事件回调函数
方法dispatch.apply(type, that, arguments)
第三个参数arguments
是一个数组,它会传递给事件回调函数
通过以上方法分发事件时,可以传递任意数据给事件回调函数,一般是传递与选择集相关的数据,例如(当前所遍历的选择集中的)元素所绑定的数据d
和索引值i