@better-scroll/shared-utils
Version:
shared-utils for BetterScroll
173 lines (147 loc) • 3.39 kB
text/typescript
import { warn } from './debug'
import { addEvent, removeEvent } from './dom'
interface Events {
[name: string]: [WithFnFunction, Object][]
}
interface EventTypes {
[type: string]: string
}
interface WithFnFunction extends Function {
fn?: Function
}
export class EventEmitter {
events: Events
eventTypes: EventTypes
constructor(names: string[]) {
this.events = {}
this.eventTypes = {}
this.registerType(names)
}
on(type: string, fn: Function, context: Object = this) {
this.hasType(type)
if (!this.events[type]) {
this.events[type] = []
}
this.events[type].push([fn, context])
return this
}
once(type: string, fn: Function, context: Object = this) {
this.hasType(type)
const magic = (...args: any[]) => {
this.off(type, magic)
const ret = fn.apply(context, args)
if (ret === true) {
return ret
}
}
magic.fn = fn
this.on(type, magic)
return this
}
off(type?: string, fn?: Function) {
if (!type && !fn) {
this.events = {}
return this
}
if (type) {
this.hasType(type)
if (!fn) {
this.events[type] = []
return this
}
let events = this.events[type]
if (!events) {
return this
}
let count = events.length
while (count--) {
if (
events[count][0] === fn ||
(events[count][0] && events[count][0].fn === fn)
) {
events.splice(count, 1)
}
}
return this
}
}
trigger(type: string, ...args: any[]) {
this.hasType(type)
let events = this.events[type]
if (!events) {
return
}
let len = events.length
let eventsCopy = [...events]
let ret
for (let i = 0; i < len; i++) {
let event = eventsCopy[i]
let [fn, context] = event
if (fn) {
ret = fn.apply(context, args)
if (ret === true) {
return ret
}
}
}
}
registerType(names: string[]) {
names.forEach((type: string) => {
this.eventTypes[type] = type
})
}
destroy() {
this.events = {}
this.eventTypes = {}
}
private hasType(type: string) {
const types = this.eventTypes
const isType = types[type] === type
if (!isType) {
warn(
`EventEmitter has used unknown event type: "${type}", should be oneof [` +
`${Object.keys(types).map((_) => JSON.stringify(_))}` +
`]`
)
}
}
}
interface EventData {
name: string
handler(e: UIEvent): void
capture?: boolean
}
export class EventRegister {
constructor(
public wrapper: HTMLElement | Window,
public events: EventData[]
) {
this.addDOMEvents()
}
destroy() {
this.removeDOMEvents()
this.events = []
}
private addDOMEvents() {
this.handleDOMEvents(addEvent)
}
private removeDOMEvents() {
this.handleDOMEvents(removeEvent)
}
private handleDOMEvents(eventOperation: Function) {
const wrapper = this.wrapper
this.events.forEach((event: EventData) => {
eventOperation(wrapper, event.name, this, !!event.capture)
})
}
private handleEvent(e: UIEvent) {
const eventType = e.type
this.events.some((event: EventData) => {
if (event.name === eventType) {
event.handler(e)
return true
}
return false
})
}
}