CKEditor5事件系统(事件优先级)

时间:2022-03-02 11:24:35

今天继续学习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 );
} );

打印出来的日志如下:

CKEditor5事件系统(事件优先级)

显然,我自定义的级别高的监听器先执行,而级别较低的监听器没有执行:

这里我修改一下*别的监听器:

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'});

这时打印出来的日志如下:

CKEditor5事件系统(事件优先级)

而级别为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'});
CKEditor5事件系统(事件优先级)

从这里可以看到如果只发出fire('foo'),那么只有一个监听器执行,而如果发出fire('foo:bar'),那么有两个监听器执行。因此如果在文档中有一个insert:p事件,那么既可以监听insert事件,也可以监听insert:p事件。这样的好处不言而喻。

下一节,我们研究事件的代理。