CKEditor5 Observable——装饰方法

时间:2022-06-01 17:38:12

上一节我们学习了在CK5中,如何绑定多个属性以及绑定多个Observable对象,今天我们学习如何装饰方法。

CKEditor5 Observable——装饰方法

 

首先,我们提出一个问题,为什么会有装饰方法呢?以及什么叫做装饰?

所谓装饰,就是在不改变原来方法功能的前提下,增加方法的功能,众所周知在java的IO流中,就有很多地方用到了装饰。

 

而在CK5中,装饰是什么意思呢?请看下面这段话:

Decorating object methods transforms them into event–driven ones without changing their original behavior.

大概意思就是在不改变原方法行为的同时,将方法转化成基于事件驱动的。下面我们用代码来说明:

import {View} from 'ckeditor5/src/ui';
export default class DecorateButton extends View {
    constructor() {
        super();
        this.type = 'button';

        const bind = this.bindTemplate;

        // this.label is observable but undefined.
        this.set( 'label' );

        // this.isOn is observable and false.
        this.set( 'isOn', false );

        // this.isEnabled is observable and true.
        this.set( 'isEnabled', true );

        this.setTemplate( {
            tag: 'button',
            attributes: {
                class: [
 
                    bind.to( 'isOn', value => value ? 'ck-on' : 'ck-off' ),
      
                    bind.if( 'isEnabled', 'ck-disabled', value => !value )
                ],
                type: this.type
            },
            children: [
                {
                    
                    text: bind.to( 'label' )
                }
            ]
        } );
        this.decorate( 'focus' );
    }
    focus( force ) {
        console.log( `Focusing button, force argument="${ force }"` );

        // Unless forced, the button will only focus when not already focused.
        if ( force || document.activeElement != this.element ) {
            this.element.focus();
            return true;
        }
        return false;
    }
}

在上面的代码中,focus方法被装饰后,DecorateButton 继承自View,因此是一个Observable对象,focus被装饰后,变成了基于事件驱动的。那么它基于事件驱动以后,究竟有什么作用呢?我们一一说明:

装饰方法的作用

1、从外部阻止方法的执行

const button = new DecorateButton();
// Render the button to create its #element.
button.render();
// The logic controlling the behavior of the button.
        button.on( 'focus', ( evt, [ isForced ] ) => {
            // Disallow forcing the focus of this button.
            if ( isForced === true ) {
                evt.stop();
            }
        }, { priority: 'high' } );
button.focus(); // -> 'Focusing button, force argument="undefined"'
button.focus( true ); // Nothing is logged, the execution has been stopped.

这里打印出的日志信息如下:

CKEditor5 Observable——装饰方法

可以看出只有button.focus()方法调用的时候,代码执行啦,第二个button.focus(true)执行的时候,被我们自己定义的监听器拦截后,通过调用evt.stop()阻止了后续方法的执行。

 

2、改变返回的值

const button = new DecorateButton();
// Render the button to create its #element.
button.render();
// The logic controlling the behavior of the button.
button.on( 'focus', ( evt, [ isForced ] ) => {
 // Pretend the button wasn't focused if the focus was forced.
            if ( isForced === true ) {
                evt.return = false;
            }
} );
console.log( button.focus() ); // -> true
console.log( button.focus( true ) ); // -> false

这里打印出来的日志信息如下:

CKEditor5 Observable——装饰方法

从日志可以看出,当button.focus()不传值的时候,返回值是原始的返回值,而当button.focus(true)执行的时候,返回的是拦截器返回的值。从日志可以看出,原始方法和监听方法都得到了执行。

我们在监听器方法中增加一个日志:

console.log('execute listener');

添加日志信息后,日志信息如下:

CKEditor5 Observable——装饰方法

从日志可以看出是先执行原始方法,然后执行监听器方法,最后返回值。

3、修改及时参数值

const button = new Button();
// Render the button to create its #element.
button.render();
// The logic controlling the behavior of the button.
button.on( 'focus', ( evt, args ) => {
   // Always force the focus.
   args[ 0 ] = true;
}, { priority: 'high' } );
button.focus(); // -> 'Focusing button, force="true"'
button.focus( true ); // -> 'Focusing button, force="true"'

这种情况下,打印出来的日志信息如下:

CKEditor5 Observable——装饰方法

不管是否传递参数,在一个高级别的监听器中,都强制修改成了true。