敲碎时间,铸造不朽的个人专栏
上一篇

CKeditor5事件系统命名空间分析

广告
选中文字可对指定文章内容进行评论啦,→和←可快速切换按钮,绿色背景文字可以点击查看评论额。
大纲

在上一节的事件系统源码中,我们留下了一个函数createEventNamespace( this, event )

今天我们来分析这个函数:

首先,我将这个函数摘取出来,放到一个utils.js文件中:

function getEvents( source ) {
	if ( !source._events ) {
		Object.defineProperty( source, '_events', {
			value: {}
		} );
	}

	return source._events;
}

function makeEventNode() {
	return {
		callbacks: [],
		childEvents: []
	};
}

function createEventNamespace( source, eventName ) {
	const events = getEvents( source );

	// First, check if the event we want to add to the structure already exists.
	if ( events[ eventName ] ) {
		// If it exists, we don't have to do anything.
		return;
	}

	// In other case, we have to create the structure for the event.
	// Note, that we might need to create intermediate events too.
	// I.e. if foo:bar:abc is being registered and we only have foo in the structure,
	// we need to also register foo:bar.

	// Currently processed event name.
	let name = eventName;
	// Name of the event that is a child event for currently processed event.
	let childEventName = null;

	// Array containing all newly created specific events.
	const newEventNodes = [];

	// While loop can't check for ':' index because we have to handle generic events too.
	// In each loop, we truncate event name, going from the most specific name to the generic one.
	// I.e. foo:bar:abc -> foo:bar -> foo.
	while ( name !== '' ) {
		if ( events[ name ] ) {
			// If the currently processed event name is already registered, we can be sure
			// that it already has all the structure created, so we can break the loop here
			// as no more events need to be registered.
			break;
		}

		// If this event is not yet registered, create a new object for it.
		events[ name ] = makeEventNode();
		// Add it to the array with newly created events.
		newEventNodes.push( events[ name ] );

		// Add previously processed event name as a child of this event.
		if ( childEventName ) {
			events[ name ].childEvents.push( childEventName );
		}

		childEventName = name;
		// If `.lastIndexOf()` returns -1, `.substr()` will return '' which will break the loop.
		name = name.substr( 0, name.lastIndexOf( ':' ) );
	}

	if ( name !== '' ) {
		// If name is not empty, we found an already registered event that was a parent of the
		// event we wanted to register.

		// Copy that event's callbacks to newly registered events.
		for ( const node of newEventNodes ) {
			node.callbacks = events[ name ].callbacks.slice();
		}

		// Add last newly created event to the already registered event.
		events[ name ].childEvents.push( childEventName );
	}
    return events;
}

module.exports = {
    createEventNamespace
}

为了理解这个方法的执行,我写了一个测试类utils.test.js

import {createEventNamespace } from '../src/utils';

test('createEventNamespace', ()=>{
    const events = createEventNamespace({},'foo:bar:des');
    expect(events.foo).toEqual({callbacks: [], childEvents: [ 'foo:bar'] });
    expect(events.foo.childEvents).toEqual([ 'foo:bar'])
    expect(events['foo:bar']).toEqual({ callbacks: [], childEvents: [ 'foo:bar:des' ] });
    expect(events['foo:bar'].childEvents).toEqual([ 'foo:bar:des' ])
    expect(events['foo:bar:des']).toEqual({ callbacks: [], childEvents: [] }); 
    expect(events['foo:bar:des'].childEvents).toEqual([])
});
test('events keys', ()=>{
    const events = createEventNamespace({},'foo:bar:des');
    const keys = Object.keys(events);
    console.log('keys:',keys)
    expect(keys).toEqual(['foo:bar:des','foo:bar','foo']);
});

各位注意了:

1、在createEventNamespace方法中,首先获取当前emitter对应的事件对象,如果在事件对象上已经存在对应的事件,那么直接返回。

2、然后看看事件是否包含命名空间的分隔符 :注意,这里在创建的时候,会创建一个数据结构:

{
	callbacks: [],
	childEvents: []
};

也就是每个事件的值对象是一个包含callbacks和childEvents两个属性的结构。

3、然后没迭代一次,分割符就会少一个,具体情况是这样的,foo:bar:des,第一步创建key为foo:bar:des的结构,然后是foo:bar,最后是foo

4、最后是设置childEvents属性,还是用第三点的例子来说,foo:bar:des这个key对象的childEvents属性为空组数,而foo:barkey对应的childEvents属性就是foo:bar:des,而fookey对象的childEvents对应的属性则是foo:bar

5、最终产生的数据结构

events: {
    'foo:bar:des': { callbacks: [], childEvents: [] },
    'foo:bar': { callbacks: [], childEvents: [ 'foo:bar:des' ] },
     foo: { callbacks: [], childEvents: [ 'foo:bar' ] }
}

好了,大家应该理解了这个函数的作用了吧

 

版权声明:著作权归作者所有。

X

欢迎加群学习交流

联系我们