Skip to content

theajack/tc-event

Repository files navigation

stars forks version downloads jsdelivr issue

author license Size TopLang Dependent test

🚀 Powerful and easy-to-use event library

Online Use | 中文 | Update Log | Feedback bug | Gitee


1. Features

  1. Typescript writing
  2. Multi-terminal support
  3. Custom event sequence, multiple trigger modes
  4. Global interception mechanism
  5. Small size, easy to use
  6. Support for creating modules to avoid event conflicts

2. Quick use

2.1 npm installation

npm i tc-event
import event from 'tc-event';

event.regist('myEvent', (data) => {
    console.log('emited!', data);
})

event.emit('myEvent', 'Aha!');

2.2 cdn

<script src="https://cdn.jsdelivr.net/npm/tc-event/tc-event.min.js"></script>
<script>
    TEvent.regist('myEvent', function (data) {
        console.log('emited!', data);
    })

    TEvent.emit('myEvent', 'Aha!');
</script>

3 api

For details, please refer to index.d.ts

export interface IEventEmitter {
    removed: boolean;
    interceptor: IEventInterceptor;
    name: string;
    getEventNames(): string[]; // 事件枚举
    getEvent(): IEventJson<CEvent>;
    getEvent(name: TEventName): CEvent;
    emit(name: TEventName, data?: any): boolean; // 触发事件
    onEmit(fn: IOnInterceptorEmit): void;
    regist: IRegistMethod;
    registObject(options: IEventRegistOption & {eventName: TEventName}): IListenerItem;
    onRegist(fn: IOnInterceptorRegist): void;
    checkEvent(name: TEventName): boolean; // 检查是否存在事件
    remove: IRemoveMethod;
    clear(name?: TEventName | TEventName[]): void;
    order(name: TEventName): number;
    registNotImmediate(name: TEventName, listener: IEventListener): IListenerItem;
    registNotImmediateOnce(name: TEventName, listener: IEventListener): IListenerItem;
    registOnce(name: TEventName, listener: IEventListener): IListenerItem;
    registSingle(name: TEventName, listener: IEventListener): IListenerItem;
}

export interface IEventStatic extends IEventEmitter {
    version: string;
    createModule (name: TModuleName): IEventEmitter;
    getModule (): IEventJson<IEventEmitter>;
    getModule (name: TModuleName): IEventEmitter;
    removeModule(name: TModuleName): void;
    clearModule(): void;
    EventEmitter: typeof EventEmitter;
}

4 Use case

4.1 checkEvent

Determine whether the event exists

const eventName = 'test-checkEvent';
const result = [];
result.push(event.checkEvent(eventName));
event.regist(eventName, () => {});
result.push(event.checkEvent(eventName));
event.emit(eventName);
result.push(event.checkEvent(eventName));
event.clear(eventName);
result.push(event.checkEvent(eventName));
event.regist(eventName, () => {});
result.push(event.checkEvent(eventName));
event.clear();
result.push(event.checkEvent(eventName));
console.log(result);
// [false, true, true, false, true, false]

4.2 clear method

Clear single or all events

const eventName = 'test-clear';
const result = [];
event.regist(eventName, () => {
    result.push(1);
});
event.emit(eventName);
event.clear(eventName);
event.emit(eventName);
event.regist(eventName, {
    immediate: false,
    listener: () => {
        result.push(2);
    }
});
event.emit(eventName);
event.clear();
event.emit(eventName);
console.log(result);
// [1, 2]

4.3 immediate parameters

The immediate parameter indicates whether the current event needs to be triggered immediately if the event has already been triggered when registering an event

const eventName = 'test-immediate';
const result = [];
event.emit(eventName);

event.regist(eventName, () => {
    result.push(1);
});
event.regist(eventName, {
    immediate: true,
    listener () { result.push(2);}
});
event.regist(eventName, {
    immediate: false,
    listener () {result.push(3);}
});
console.log(result);
// [1, 2]

4.4 index parameter

The index parameter indicates the position where you want to insert when registering an event

const eventName = 'test-order';
    
const result = [];
event.regist(eventName, () => {
    result.push(1); // 1
});
event.regist(eventName, () => {
    result.push(2); // 1 2
});
event.regist(eventName, () => {
    result.push(3); // 1 2 3
});
event.regist(eventName, () => {
    result.push(4); // 1 2 3 4
});
event.regist(eventName, {
    index: 0,  // 5 1 2 3 4
    listener () {result.push(5);}
});
event.regist(eventName, {
    index: 2, // 5 1 6 2 3 4
    listener () {result.push(6);}
});
event.regist(eventName, {
    index: 1, // 5 7 1 6 2 3 4
    listener () {result.push(7);}
});
event.regist(eventName, {
    index: 100, // 5 7 1 6 2 3 4 8
    listener () {result.push(8);}
});
event.regist(eventName, {
    index: -3, // 9 5 7 1 6 2 3 4 8
    listener () {result.push(9);}
});
event.emit(eventName);
console.log(result);
// [9, 5, 7, 1, 6, 2, 3, 4, 8]

4.5 interceptor

Global interceptor, support onRegist and onEmit

const eventName1 = 'test-interceptor1';
const eventName2 = 'test-interceptor2';
const result = [];
event.onRegist(({name, item}) => {
    result.push(`onRegist: ${name}`);
});
event.onEmit(({name, item, data, firstEmit}) => {
    result.push(`onEmit: ${name} ${data} ${firstEmit}`);
});
event.regist(eventName1, () => {});
event.regist(eventName2, () => {});
event.emit(eventName1, `${eventName1} data`);
event.emit(eventName2, `${eventName2} data`);
event.emit(eventName2, `${eventName2} data2`);
console.log(result);
/*
    [
        'onRegist: test-interceptor1',
        'onRegist: test-interceptor2',
        'onEmit: test-interceptor1 test-interceptor1 data true',
        'onEmit: test-interceptor2 test-interceptor2 data true',
        'onEmit: test-interceptor2 test-interceptor2 data2 false'
    ]
*/

4.6 once parameter

once parameter is only triggered sequentially

const eventName = 'test-once';
const result = [];

event.regist(eventName, () => {
    result.push(1);
});
event.regist(eventName, {
    once: true,
    listener () { result.push(2);}
});
event.regist(eventName, {
    once: false,
    listener () {result.push(3);}
});
event.emit(eventName);
event.emit(eventName);
console.log(result);
// [1, 2, 3, 1, 3]

4.7 times parameter

The times parameter is the number of times the monitor is triggered

const eventName = 'test-times';
const result = [];

event.regist(eventName, {
    times: 1,
    listener () { result.push(1);}
});
event.regist(eventName, {
    times: 2,
    listener () { result.push(2);}
});
event.regist(eventName, {
    times: 3,
    listener () { result.push(3);}
});
event.emit(eventName);
event.emit(eventName);
event.emit(eventName);
event.emit(eventName);
// [1, 2, 3, 2, 3, 3]

4.8 order parameter

Control the sequence number of the insertion event (different from the index parameter)

const eventName = 'test-order';
            
const result = [];
event.regist(eventName, () => {
    result.push(1); // 1
});
event.regist(eventName, () => {
    result.push(2); // 1 2
});
event.regist(eventName, {
    order: 0, // 0 1 2
    listener () {result.push(3);}
});
event.regist(eventName, {
    order: 1, // 0 1 *1 2
    listener () {result.push(4);}
});
event.regist(eventName, {
    order: 1, // 0 1 *1 **1 2
    listener () {result.push(5);}
});
event.regist(eventName, {
    order: 1, // 0 ***1 1 *1 **1 2
    orderBefore: true,
    listener () {result.push(6);}
});
event.regist(eventName, {
    order: 10, // 0 ***1 1 *1 **1 2 10
    listener () {result.push(7);}
});
event.regist(eventName, () => { // 0 ***1 1 *1 **1 2 3 10
    result.push(8);
});
event.emit(eventName);
console.log(result);

4.9 single parameter

Singleton monitoring mode, enabling the single parameter for an event name will overwrite all previous monitoring functions for the event

And after this event, there is no need to carry the single parameter

When the single parameter is enabled, the index order orderBefore parameter is invalid

const eventName = 'test-single';
const result = [];

event.regist(eventName, () => {
    result.push(1);
});
event.emit(eventName);
// Test coverage old method
event.regist(eventName, {
    single: true,
    immediate: false,
    listener: () => {
        result.push(2);
    }
});
event.emit(eventName);
event.clear(eventName);

event.regist(eventName, {
    single: true,
    listener () { result.push(3);}
});
event.regist(eventName, {
    single: true,
    listener () { result.push(4);}
});
event.emit(eventName);
// Test single parameter cache
event.regist(eventName, {
    immediate: false,
    listener () { result.push(5);}
});
event.emit(eventName);
console.log(result);
// [1, 2, 4, 5]

4.10 name parameter

The name parameter is used to add a parameter to a monitor

The default value is eventName + id

const eventName = 'test-name';
    
const item1 = event.regist(eventName, () => {
});
const item2 = event.regist(eventName, {
    name: 'listener-name',
    listener () {}
});
// item1.name === 'test-name-1'
// item2.name === 'listener-name'

4.11 head parameters

The head parameter is used to add the listener to the event head

const eventName = 'test-head';
const result = [];
event.regist(eventName, () => {
    result.push(1);
});
event.regist(eventName, {
    order: -1,
    listener () {result.push(2);}
});
event.regist(eventName, {
    index: -1,
    listener () {result.push(3);}
});
event.regist(eventName, {
    head: true,
    listener () {result.push(4);}
});
event.regist(eventName, {
    head: true,
    listener () {result.push(5);}
});
event.emit(eventName);
// result: [5, 4, 3, 2, 1]

4.12 tail parameters

The tail parameter is used to add the listener to the end of the event

const eventName = 'test-tail';
const result = [];
event.regist(eventName, () => {
    result.push(1);
});
event.regist(eventName, {
    order: 100,
    listener () {result.push(2);}
});
event.regist(eventName, {
    index: 100,
    listener () {result.push(3);}
});
event.regist(eventName, {
    listener () {result.push(4);}
});
event.regist(eventName, {
    tail: true,
    listener () {result.push(5);}
});
event.regist(eventName, {
    tail: true,
    listener () {result.push(6);}
});
event.emit(eventName);
// result: [1, 4, 2, 3, 5, 6]

4.13 order method

Get the serial number of a monitor

const eventName = 'test-order-fn';
const result = [];

event.regist(eventName, () => {
    result.push(1);
});
event.regist(eventName, () => {
    result.push(2);
});
const e1 = event.regist(eventName, () => {
    result.push(3);
});
const e2 = event.regist(eventName, {
    order: 1,
    listener () { result.push(4);}
});
event.regist(eventName, () => {
    result.push(5);
});
event.emit(eventName);
console.log([result, event.order(eventName), e1.order, e2.order]);
// [[1, 4, 2, 3, 5], 4, 3, 1

4.14 remove method

Remove event listener

const eventName = 'test-remove';
const result = [];
const l4 = () => { result.push(4); };
const l5 = () => { result.push(5); };
const l6 = () => { result.push(6); };
const l7 = () => { result.push(7); };
event.regist(eventName, () => {
    result.push(1);
});
event.regist(eventName, () => {
    result.push(2);
});
event.regist(eventName, () => {
    result.push(3);
    event.remove(eventName, l4, true);
    event.remove(eventName, l5);
    event.regist(eventName, l7);
});
event.regist(eventName, l4);
event.regist(eventName, l5);
event.regist(eventName, l6);
event.remove(eventName, l6);
event.emit(eventName);
event.emit(eventName);
console.log(result);
// [1, 2, 3, 7, 5, 1, 2, 3, 7, 7]

4.15 registNotImmediate

event.registNotImmediate('xxx', ()=>{})
// equals
event.regist('xxx', {
    immediate: false,
    listener: ()=>{}
})

4.16 registOnce

event.registOnce('xxx', ()=>{})
// equals
event.regist('xxx', {
    once: true,
    listener: ()=>{}
})

4.17 registNotImmediateOnce

event.registNotImmediateOnce('xxx', ()=>{})
// equals
event.regist('xxx', {
    immediate: false,
    once: true,
    listener: ()=>{}
})

4.18 registSingle

event.registSingle('xxx', ()=>{})
// equals
event.regist('xxx', {
    single: true,
    listener: ()=>{}
})

4.19 Monitor callback parameters

The second parameter of the monitoring function is a json, which contains three attributes

  1. firstEmit indicates whether the monitor is triggered for the first time
  2. remove is the method to remove the current monitor
  3. clear is the method to remove the current event
  4. item is the current monitoring object
event.regist('xxx', (data, {firstEmit, item, remove, clear})=>{

})

4.20 Chain call

The regist function will enable chained calls when referring to the incoming event name

All parameters can be called by chain, all apis are optional, and finally need to be triggered through the listen method

event.regist('xxx')
    .index(1)
    .order(1)
    .orderBefore()
    .notImmediate()
    .single()
    .once()
    .times(1)
    .listener()
    .name('xxx')
    .head()
    .tail()
    .listen();

The declaration file is as follows

interface IEventLink {
    single: (single: boolean) => IEventLink;
    notImmediate: (immediate: boolean) => IEventLink;
    once: (once: boolean) => IEventLink;
    index: (index: number) => IEventLink;
    order: (order: number) => IEventLink;
    orderBefore: (orderBefore: boolean) => IEventLink;
    listener: (listener: IEventListener) => IEventLink;
    name: (name: string) => IEventLink;
    head: () => IEventLink;
    tail: ()=> IEventLink;
    times: (times: number)=> IEventLink;
    listen: (listener?: IEventListener) => IListenerItem;
}

4.21 event module

  1. createModule
const result = [];
const name = 'module_event';
const moduleA = event.createModule('A');
const moduleB = event.createModule('B');

moduleA.regist(name, data => {result.push('A' + data);});
moduleB.regist(name, data => {result.push('B' + data);});

moduleA.emit(name, 1);
moduleA.emit(name, 2);
console.log(result);
  1. getModule
event.createModule('A');
event.createModule('B');

console.log([
    event.getModule('A').moduleName,
    event.getModule('B').moduleName,
]);