向上转换 - 视图到模型
# 简介
将视图转换为模型的过程称为向上转换。
向上转换过程每当任何数据被加载到编辑器中时都会发生。
传入数据成为视图,然后通过注册的转换器转换为模型。
如果你只想快速启用 CKEditor 5 功能明确不支持的一些常见 HTML 标签,可以使用通用 HTML 支持功能,而不是编写你自己的自定义向上转换器。
# 注册转换器
要指示引擎如何将特定视图元素转换为模型元素,你需要使用editor.conversion.for( 'upcast' )
方法注册一个向上转换器
editor.conversion
.for( 'upcast' )
.elementToElement( {
view: 'p',
model: 'paragraph'
} );
上面的转换器将处理所有<p>
视图元素转换为<paragraph>
模型元素的转换。
你刚刚了解了elementToElement()
向上转换转换助手方法!更多助手将在后面的章节中介绍。
# 向上转换管道
与向下转换不同的是,你只需要处理数据管道和编辑管道,向上转换过程只发生在数据管道中,被称为数据向上转换。
编辑视图只能通过首先更改模型来更改,因此编辑管道只需要向下转换过程。
前面的代码示例为两个管道同时注册了一个转换器。这意味着<paragraph>
模型元素将同时在数据视图和编辑视图中转换为<p>
视图元素。
# 转换为文本属性
表示内联文本格式的视图元素(例如<strong>
或<i>
)需要转换为模型文本节点上的属性。
要注册此类转换器,请使用elementToAttribute()
方法
editor.conversion
.for( 'upcast' )
.elementToAttribute( {
view: 'strong',
model: 'bold'
} );
用<strong>
标签包装的文本将被转换为一个模型文本节点,并应用一个bold
属性,如所示
加粗文本
如果你需要将属性从视图元素“复制”到模型元素,请使用attributeToAttribute()
方法。
模型元素必须有自己的转换器注册,否则属性将无法复制到任何地方。
editor.conversion
.for( 'upcast' )
.attributeToAttribute( {
view: 'src',
model: 'source'
} );
假设编辑器中的一些其他功能注册了<img>
到<image>
模型元素的向上转换器,你可以扩展此功能以允许src
属性。此属性将被转换为模型元素上的source
属性,如以下代码段所示

这只是一个例子。实际上,图像元素和源属性的支持由图像功能提供,因此你无需自己编写<image source="xxx">
到<img src="xxx">
元素转换。
# 转换为元素
将视图元素转换为相应的模型元素可以通过使用elementToElement()
方法注册转换器来实现
editor.conversion
.for( 'upcast' )
.elementToElement( {
view: {
name: 'div',
classes: [ 'example' ]
},
model: 'example'
} );
此转换器将处理所有<div class="example">
视图元素转换为<example>
模型元素的转换。
使用你自己的自定义模型元素需要先在模式中定义它。
# 转换结构
正如你在上一章中所学,单个模型元素可以向下转换为多个视图元素的结构。
相反的过程将不得不检测该结构(例如,主元素)并将其转换为一个简单的模型元素。
对于向上转换,没有structureToElement()
助手可用。要为整个结构注册一个向上转换器并创建一个单个模型元素,你必须使用基于事件的 API。以下示例展示了如何实现它
editor.conversion.for( 'upcast' ).add( dispatcher => {
// Look for every view <div> element.
dispatcher.on( 'element:div', ( evt, data, conversionApi ) => {
// Get all the necessary items from the conversion API object.
const {
consumable,
writer,
safeInsert,
convertChildren,
updateConversionResult
} = conversionApi;
// Get view item from data object.
const { viewItem } = data;
// Define elements consumables.
const wrapper = { name: true, classes: 'wrapper' };
const innerWrapper = { name: true, classes: 'inner-wrapper' };
// Tests if the view element can be consumed.
if ( !consumable.test( viewItem, wrapper ) ) {
return;
}
// Check if there is only one child.
if ( viewItem.childCount !== 1 ) {
return;
}
// Get the first child element.
const firstChildItem = viewItem.getChild( 0 );
// Check if the first element is a <div>.
if ( !firstChildItem.is( 'element', 'div' ) ) {
return;
}
// Tests if the first child element can be consumed.
if ( !consumable.test( firstChildItem, innerWrapper ) ) {
return;
}
// Create model element.
const modelElement = writer.createElement( 'myElement' );
// Insert element on a current cursor location.
if ( !safeInsert( modelElement, data.modelCursor ) ) {
return;
}
// Consume the main outer wrapper element.
consumable.consume( viewItem, wrapper );
// Consume the inner wrapper element.
consumable.consume( firstChildItem, innerWrapper );
// Handle children conversion inside inner wrapper element.
convertChildren( firstChildItem, modelElement );
// Necessary function call to help setting model range and cursor
// for some specific cases when elements being split.
updateConversionResult( modelElement, data );
} );
} );
此转换器将检测所有<div class="wrapper"><div class="inner-wrapper"><p>...</p></div></div>
结构(通过扫描外部<div>
并将其转换为单个<myElement>
模型元素)。效果应返回如下
示例结构
使用你自己的自定义模型元素需要先在模式中定义它。
# 进一步阅读
如果你想了解本指南中提到的向上转换助手的更多信息,我们已经为你总结了它们,包括完整的描述和示例。我们还建议你查看向下转换指南,了解如何将编辑器模型状态转换为数据输出和编辑视图。
我们每天都在努力使我们的文档保持完整。你发现过时信息了吗?是否缺少某些内容?请通过我们的问题跟踪器报告。
随着版本 42.0.0 的发布,我们重写了许多文档以反映新的导入路径和功能。感谢你的反馈,帮助我们确保文档的准确性和完整性。