事件处理
我们提供了一些新的特性来提高开发效率。
简洁模式
一种简洁的事件处理方式:on__() 、 off__(), 可以通过参数绑定 this, 一次可以 off 多个不同的侦听事件。
命名规则
事件名称常量对应的字面值遵循如下规则:
PointerEvent.DOWN = 'pointer.down' // 事件类型.事件名称, 提高可读性
ZoomEvent.ZOOM: 'zoom' // 事件类型与事件名称一样,可以省略
ZoomEvent.START: 'zoom.start'
ZoomEvent.END: 'zoom.end'
// 例外, 以下 PointerEvent 事件不用加 pointer 前缀
'tap'|'click'|'doubleclick'|'longpress'|'longtap'
使用字面值代替常量
import { Leafer } from 'leafer-ui'
const leafer = new Leafer({ view: window })
leafer.on('pointer.down', () => {
console.log('down')
})
命名修改
修改事件名称常量,如 PointerEvent.DOWN = 'pointerdown',可以改变事件名称字面值, 一般用于兼容您已有的业务代码。
冒泡与捕获
UI 事件均支持冒泡与捕获阶段, 通过 e.stop() 、 e.stopNow() ) 来阻止事件传递。
新增属性
相关按钮是否被按下: left、 middle、right、spaceKey。
import { Leafer, PointerEvent } from 'leafer-ui'
const leafer = new Leafer({ view: window })
leafer.on(PointerEvent.DOWN, (e: PointerEvent) => {
if (e.left) {
console.log('当前只按下鼠标左键')
}
})
配对事件
在做 web 开发时,经常会遇到这样的问题:比如元素 pointer.down
触发后,因为拖拽或pointer.cancel
,不能完全保证元素会触发 pointer.up
。
针对这种情况,我们在设计事件系统时进行了相关的事件处理,尤其是针对拖拽过程,确保元素 pointer.down
触发后,即使移动了位置抬起、取消,元素也一定会触发 pointer.up
。
关键方法
on(type: string | string[], listener: IEventListener, options?: IEventListenerOptions | boolean): void
侦听事件
import { Leafer, Rect, PointerEvent } from 'leafer-ui'
const leafer = new Leafer({ view: window })
const rect = new Rect({
x: 100,
y: 100,
width: 200,
height: 200,
fill: '#32cd79', // 背景色
draggable: true,
})
leafer.add(rect)
// bubble
rect.on(PointerEvent.DOWN, () => {
console.log('冒泡事件')
})
// capture
function downCapture(): void {
console.log('捕获事件')
}
rect.on(PointerEvent.DOWN, downCapture, true)
// 等于 rect.on(PointerEvent.DOWN, downCapture, { capture: true })
off(type: string | string[], listener: IEventListener, options?: IEventListenerOptions | boolean): void
关闭侦听事件
once(type: string | string[], listener: IEventListener, capture?: boolean): void
只侦听一次事件
function upOnce(): void {
console.log('只触发一次up')
}
rect.once(PointerEvent.DOWN, upOnce)
// 等于 rect.on(PointerEvent.DOWN, downCapture, { once: true })
emit(type: string, event?: IEvent | IObject, capture?: boolean): void
手动广播事件, event 参数可以为一个自定义的 object 数据对象
rect.on('customEvent', (data) => {
console.log(data.text)
})
rect.emit('customEvent', { text: '这是一个自定义的事件' })
emitEvent(event?: IEvent, capture?: boolean): void
手动触发事件,event 参数必须为 IEvent 对象
rect.emitEvent(new PointerEvent())
hasEvent(type: string, capture?: boolean): boolean
检查当前元素是否包含某种事件类型,如: PointerEvent.DOWN
capture 不存在时,将同时检查冒泡事件和捕获事件
if (rect.hasEvent(PointerEvent.DOWN)) {
console.log('rect已侦听pointerdown事件')
}
简洁方法
on__(type: string | string[], listener: IEventListener, bind?: IObject, options?: IEventListenerOptions | boolean): IEventListenerId
侦听事件, 相对于 on()增加了 this 的 bind 对象,并返回侦听 id 用于 off(id)
off__(id: IEventListenerId | IEventListenerId[]): void
关闭侦听事件
使用简洁模式的事件侦听示例:
import { Leafer, Rect, PointerEvent, IEventListenerId } from 'leafer-ui'
class RectListener {
private rect: Rect
private events: IEventListenerId[]
constructor(rect: Rect) {
this.rect = rect
this.addListener()
}
private addListener(): void {
const { rect } = this
this.events = [
rect.on__(PointerEvent.ENTER, this.enter, this),
rect.on__(PointerEvent.LEAVE, this.leave, this),
rect.on__(PointerEvent.DOWN, this.down, this),
rect.on__(PointerEvent.UP, this.up, this),
]
}
private removeListener(): void {
this.rect.off__(this.events)
}
private enter(): void {
this.rect.fill = '#42dd89'
}
private leave(): void {
this.rect.fill = '#32cd79'
}
private down(): void {
this.rect.fill = '#229d49'
}
private up(): void {
this.rect.fill = '#42dd89'
}
public destroy(): void {
this.removeListener()
this.rect = undefined
}
}
const leafer = new Leafer({ view: window })
const leaf = new Rect({
x: 100,
y: 100,
width: 200,
height: 200,
fill: '#32cd79',
draggable: true,
})
leafer.add(leaf)
new RectListener(leaf)
对比原始模式:
import { Leafer, Rect, PointerEvent } from 'leafer-ui'
class RectListener {
private rect: Rect
constructor(rect: Rect) {
this.rect = rect
this.addListener()
}
private addListener(): void {
const { rect } = this
this.enter = this.enter.bind(this)
this.leave = this.leave.bind(this)
this.down = this.down.bind(this)
this.up = this.up.bind(this)
rect.on(PointerEvent.ENTER, this.enter)
rect.on(PointerEvent.LEAVE, this.leave)
rect.on(PointerEvent.DOWN, this.down)
rect.on(PointerEvent.UP, this.up)
}
private removeListener(): void {
const { rect } = this
rect.off(PointerEvent.ENTER, this.enter)
rect.off(PointerEvent.LEAVE, this.leave)
rect.off(PointerEvent.DOWN, this.down)
rect.off(PointerEvent.UP, this.up)
}
private enter(): void {
this.rect.fill = '#42dd89'
}
private leave(): void {
this.rect.fill = '#32cd79'
}
private down(): void {
this.rect.fill = '#229d49'
}
private up(): void {
this.rect.fill = '#42dd89'
}
public destroy(): void {
this.removeListener()
this.rect = undefined
}
}
const leafer = new Leafer({ view: window })
const leaf = new Rect({
x: 100,
y: 100,
width: 200,
height: 200,
fill: '#32cd79',
draggable: true,
})
leafer.add(leaf)
new RectListener(leaf)
简洁模式下的代码量更少, 原始模式下的性能更好,占用内存少, 请根据情况灵活使用