今天继续学习CK5的事件系统,上一节我们知道了怎么绑定和取消绑定事件的两种方法,知道在一个emitter上对一个同名事件可以绑定多个回调函数,自然问题来了,这些函数的执行顺序是怎么样的呢?
CK5的事件监听优先级
实际上,对于一个同名事件,CK5提供了事件优先级功能,如下代码所示
AnyClass.on( 'eventName', ( eventInfo, ...args ) => { console.log('execute event one') } );
AnyClass.on( 'eventName', ( eventInfo, ...args ) => { console.log('execute event two') } );
AnyClass.on( 'eventName', ( eventInfo, ...args ) => { console.log('execute event three') } );
AnyClass.fire('eventName')
这里没有指定优先级的情况下,谁先绑定,那么就谁先执行。CK5为了解决自定义执行的问题,在绑定的时候,提供了第三个参数priority:
AnyClass.on( 'eventName', ( eventInfo, ...args ) =>
{ console.log('execute event one') } ,{ priority: 'high' });
AnyClass.on( 'eventName', ( eventInfo, ...args ) => { console.log('execute event two') },
,{ priority: 'low' }
);
AnyClass.on( 'eventName', ( eventInfo, ...args ) => { console.log('execute event three') } , ,{ priority: 'highest' }
);
AnyClass.fire('eventName')
因此,有了优先级这个参数,我们对回调函数的执行,有了更多的控制:
CK5的事件系统总共提供了5个优先级:
highest
high
normal
low
lowest
注意:如果任何一个事件监听器停止执行,那么其他监听器都不会被执行,包括那些优先级较低的监听器。
CK5监听器阻止执行
this.listenTo(editor.editing.view.document, 'clipboardInput',( evt, data ) =>{
console.log('execute low');
},{priority: 'low'});
this.listenTo(editor.editing.view.document, 'clipboardInput',( evt, data ) =>{
console.log('execute high');
},{priority: 'high'});
this.listenTo(editor.editing.view.document, 'clipboardInput',( evt, data ) =>{
console.log('execute highest');
},{priority: 'highest'});
//另外一个是监听粘贴功能的代码
this.listenTo( editor.editing.view.document, 'clipboardInput', ( evt, data ) => {
console.log('clipboardInput');
let insertionRange = model.createRange( model.document.selection.anchor );
// Use target ranges in case this is a drop.
if ( data.targetRanges ) {
insertionRange = editor.editing.mapper.toModelRange( data.targetRanges[ 0 ] );
}
if ( !insertionRange.start.parent.is( 'element', 'newCodeBlock' ) ) {
return;
}
const text = data.dataTransfer.getData( 'text/plain' );
const writer = new UpcastWriter( editor.editing.view.document );
// Pass the view fragment to the default clipboardInput handler.
data.content = rawSnippetTextToViewDocumentFragment( writer, text );
} );
打印出来的日志如下:
显然,我自定义的级别高的监听器先执行,而级别较低的监听器没有执行:
这里我修改一下*别的监听器:
this.listenTo(editor.editing.view.document, 'clipboardInput',( evt, data ) =>{
console.log('execute highest');
console.log(evt.name);
console.log(evt.source);
evt.stop();
},{priority: 'highest'});
这时打印出来的日志如下:
而级别为high的监听器没有执行,只有最高界别的代码执行。同样的,我们还可以获取事件的名字和事件的源头。
this.listenTo(editor.editing.view.document, 'clipboardInput',( evt, data ) =>{
console.log('execute highest');
evt.return = 'return value';
},{priority: 'highest'});
事件还可以有一个返回值,当所有监听器执行完成后,fire方法可以或者这个返回值。
监听命名空间事件
命名空间事件是使用:来实现的
这里我们使用上一节定义的来AnyClass来说明这个问题:
import EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';
import mix from '@ckeditor/ckeditor5-utils/src/mix';
export default class AnyClass {
// ...
}
mix( AnyClass, EmitterMixin );
这里我只用剪贴板的复制功能来验证命名空间事件的使用
this.listenTo(editor.editing.view.document, 'clipboardInput',( evt, data ) =>{
console.log('execute highest');
evt.return = 'return value';
let anyClass = new AnyClass();
anyClass.on( 'foo', () => { console.log('foo'); } );
anyClass.on( 'foo:bar', () => { console.log('foo:bar'); } );
anyClass.on( 'foo:bar:baz', () => { console.log('foo:bar:baz'); } );
anyClass.fire('foo');
anyClass.fire('foo:bar');
},{priority: 'highest'});
从这里可以看到如果只发出fire('foo'),那么只有一个监听器执行,而如果发出fire('foo:bar'),那么有两个监听器执行。因此如果在文档中有一个insert:p事件,那么既可以监听insert事件,也可以监听insert:p事件。这样的好处不言而喻。
下一节,我们研究事件的代理。