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

CKEditor5——UI理解

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

CKEditor5——UI理解

今天我们开始认识CK5中的UI,首先我们还是认识一些基础类,今天开始认识的第一个类比较简单,那就是

ViewCollection,首先我们看看代码:

export default class ViewCollection extends Collection {
 	constructor( initialItems = [] ) {
		super( initialItems, {
			// An #id Number attribute should be legal and not break the `ViewCollection` instance.
			// https://github.com/ckeditor/ckeditor5-ui/issues/93
			idProperty: 'viewUid'
		} );

		// Handle {@link module:ui/view~View#element} in DOM when a new view is added to the collection.
		this.on( 'add', ( evt, view, index ) => {
			this._renderViewIntoCollectionParent( view, index );
		} );

		// Handle {@link module:ui/view~View#element} in DOM when a view is removed from the collection.
		this.on( 'remove', ( evt, view ) => {
			if ( view.element && this._parentElement ) {
				view.element.remove();
			}
		} );

		/**
		 * A parent element within which child views are rendered and managed in DOM.
		 *
		 * @protected
		 * @member {HTMLElement}
		 */
		this._parentElement = null;
	}
}

我们之前分析过Collection类,我们的ViewCollection类继承自Collection,因此它具有Collection的一切功能,此外就是增添了往集合添加或者删除View元素的时候的逻辑。

首先,我们需要明白的是这个集合是管理View的一个集合,因此这个集合需要有一个所有集合的父元素,可以看见this._parentElement这个属性就是存储集合的父元素,其次,应该不难猜想构造函数initialItems

应该是一个包含View的数组或者可迭代对象。

我们还是重点看看this._renderViewIntoCollectionParent( view, index )

_renderViewIntoCollectionParent( view, index ) {
	if ( !view.isRendered ) {
		view.render();
	}

	if ( view.element && this._parentElement ) {
		this._parentElement.insertBefore( view.element, this._parentElement.children[ index ] );
	}
}

其实这个方法主要就是渲染指定的view元素,并且将此元素添加到父元素中。因此我们可以知道只要往集合中添加元素,它会立即渲染到视图。

我们再来看看另一个代理方法:delegate( ...events )

delegate( ...events ) {
	if ( !events.length || !isStringArray( events ) ) {
		/**
		 * All event names must be strings.
		 *
		 * @error ui-viewcollection-delegate-wrong-events
		 */
		throw new CKEditorError(
			'ui-viewcollection-delegate-wrong-events',
				this
		);
	}

	return {
	  /**
		* Selects destination for {@link module:utils/emittermixin~Emitter#delegate} events.
		*
		* @memberOf module:ui/viewcollection~ViewCollection#delegate
	    * @function module:ui/viewcollection~ViewCollection#delegate.to
	    * @param {module:utils/emittermixin~Emitter} dest An `Emitter` instance which is
		* the destination for delegated events.
		*/
		to: dest => {
			// Activate delegating on existing views in this collection.
			for ( const view of this ) {
				for ( const evtName of events ) {
					view.delegate( evtName ).to( dest );
				}
			}

			// Activate delegating on future views in this collection.
			this.on( 'add', ( evt, view ) => {
				for ( const evtName of events ) {
					view.delegate( evtName ).to( dest );
				}
			} );

			// Deactivate delegating when view is removed from this collection.
			this.on( 'remove', ( evt, view ) => {
				for ( const evtName of events ) {
					view.stopDelegating( evtName, dest );
				}
			} );
		}
	};
}

这个方法的作用就是将集合中的每个View的指定事件代理给其他外部的View元素。同时在添加元素和删除View元素的时候也要代理或者取消代理相关的事件。看看例子

const viewA = new View();
const viewB = new View();
const viewC = new View();

const views = parentView.createCollection();

views.delegate( 'eventX' ).to( viewB );
views.delegate( 'eventX', 'eventY' ).to( viewC );

views.add( viewA );

viewA.fire( 'eventX', customData );

viewA.fire( 'eventY', customData );

这里需要注意的是,事件的触发是由集合中的View触发的,并且被代理的视图需要监听事件才有作用。

 

最后一个有意思方法就是

setParent( elementOrDocFragment ) {
	this._parentElement = elementOrDocFragment;

	// Take care of the initial collection items passed to the constructor.
	for ( const view of this ) {
		this._renderViewIntoCollectionParent( view );
	}
}

这个方法的作用就是修改集合视图的父元素,并且将子节点渲染到新的父元素之下。这个有啥作用呢?我的猜想就是可以提高集合视图的复用效果,比如我写了一个不错的集合视图UI,当我需要把它切换到新的节点位置的时候,我只需要修改父节点就OK。

 

 

 

 

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

X

欢迎加群学习交流

联系我们