CKEditor5事件系统(事件优先级)
今天继续学习CK5的事件系统,上一节我们知道了绑定和取消绑定事件的两种方法,知道在一个emitter上一个同名事件可以绑定多个回调函数,自然问题来了,这些函数的执行顺序是怎么样的呢?
CK5的事件监听优先级
实际上,对于一个同名事件,CK5提供了事件优先级功能,如下代码所示
const anyClass = new AnyClass();
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:
const anyClass = new AnyClass();
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 );
} );
打印出来的日志如下:
<figure class="image"></figure>显然,我自定义的级别高的监听器先执行,而级别较低的监听器没有执行:
这里我修改一下最高级别的监听器:
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事件的函数也会执行。这样的好处不言而喻。
下一节,我们研究事件的代理。
总结一下
1、同名事件的不同回调函数可以通过priority参数控制执行顺序
2、优先级高的回调函数可以通过调用evt.stop()方法来阻止后续回调函数的执行
3、可以通过对事件名称使用命名空间来做到发送一个事件来达到多个回调函数执行的功能。