Contribute to this guide

guide向下转换助手 - 模型到视图转换

本文列出了向下转换中可用的所有编辑器助手。

# 元素到元素转换助手

将模型元素转换为视图元素是转换最常见的情况。它用于创建我们称之为“容器元素”的视图元素,例如<p><h1>

使用elementToElement()助手时,单个模型元素将被转换为单个视图元素。此模型元素的子元素需要定义自己的转换器,引擎将递归地转换它们并将它们插入到创建的视图元素中。

# 基本元素到元素转换

如果你想将模型元素转换为简单的视图元素,没有任何额外的属性,只需通过转换器提供它们的名称,如以下示例所示

editor.conversion
    .for( 'downcast' )
    .elementToElement( {
        model: 'paragraphSeparator',
        view: 'hr'
} );

# 使用视图元素定义

有时你可能需要输出具有某些属性的视图元素,例如类名。为了实现这一点,你可以在view属性中提供一个元素定义

editor.conversion
    .for( 'downcast' )
    .elementToElement( {
        model: 'fancyParagraph',
        view: {
            name: 'p',
            classes: 'fancy'
        }
    } );

查看ElementDefinition 文档以了解更多详细信息。

# 使用回调创建视图元素

使用回调编写上一节中转换器的另一种方法如下所示

editor.conversion
    .for( 'downcast' )
    .elementToElement( {
        model: 'fancyParagraph',
        view: ( modelElement, { writer } ) => {
            return writer.createContainerElement(
                'p', { class: 'fancy' }
            );
        }
    } );

这里,视图回调的第二个参数是DowncastConversionApi对象。它包含许多在编写更复杂的转换器时可能会有用的属性和方法。

回调应该返回单个容器元素。此元素不应包含任何子元素,除了 UI 元素。如果你想创建更丰富的结构,请使用elementToStructure()方法。

# 处理具有属性的模型元素

如果视图元素不仅依赖于模型元素本身,还依赖于它的属性,则需要在model属性中指定这些属性。

editor.conversion
    .for( 'downcast' )
    .elementToElement( {
        model: {
            name: 'heading',
            attributes: [ 'level' ]
        },
        view: ( modelElement, { writer } ) => {
            return writer.createContainerElement(
                'h' + modelElement.getAttribute( 'level' )
            );
        }
    } );

如果你忘记指定这些属性,转换器仍然可以用于插入模型元素部分,但它不会处理属性值的任何更改。

# 更改转换器优先级

如果已经存在具有重叠model模式的其他转换器,你可以优先考虑你的转换器来覆盖它们。为此,请使用converterPriority属性

editor.conversion
    .for( 'downcast' )
    .elementToElement( {
        model: 'userComment',
        view: 'div'
    } );

editor.conversion
    .for( 'downcast' )
    .elementToElement( {
        model: 'userComment',
        view: 'article',
        converterPriority: 'high'
    } );

在上面的示例中,第一个转换器没有显式设置优先级,因此它假设默认优先级,即normal。第二个转换器通过将优先级设置为high来覆盖它。同时使用这两个转换器将导致<userComment>元素被转换为<article>元素。

这个解决方案也可能很方便,如果你想让你的转换器在给定元素的其他转换器不存在时充当后备(例如,插件尚未加载)。可以通过将converterProperty设置为low轻松实现。

# 元素到结构转换助手

将单个模型元素转换为多个视图元素(视图元素的结构)。

# 处理空模型元素

要将单个模型元素horizontalLine转换为以下结构

<div class="horizontal-line">
    <hr />
</div>

你可以使用类似于此的转换器

editor.conversion
    .for( 'downcast' )
    .elementToStructure( {
        model: 'horizontalLine',
        view: ( modelElement, { writer } ) => {
            return writer.createContainerElement( 'div', { class: 'horizontal-line' }, [
                writer.createEmptyElement( 'hr' )
            ] );
        }
} );

请注意,在这个示例中,我们创建了两个元素,这无法通过使用前面提到的elementToElement()助手来实现。

对于编辑器用户来说,与复杂结构交互的最佳方式是作为独立实体进行交互,并在复制、粘贴和编辑时保持完整。CKEditor 5 通过小部件 API允许这样做。如果你想了解如何在elementToStructure()之上使用它,请务必查看实现块小部件教程。

# 处理模型元素的子元素

上面的示例使用了一个空模型元素。如果你的模型元素可能包含子元素,则需要指定这些子元素在视图中的放置位置。为此,请使用writer.createSlot()助手。

editor.conversion
    .for( 'downcast' )
    .elementToStructure( {
        model: 'wrappedParagraph',
        view: ( modelElement, conversionApi ) => {
            const { writer } = conversionApi;
            const paragraphViewElement = writer.createContainerElement( 'p', {}, [
                writer.createSlot()
            ] );

            return writer.createContainerElement( 'div', { class: 'wrapper' }, [
                paragraphViewElement
            ] );
        }
    } );

对于编辑器用户来说,与复杂结构交互的最佳方式是作为独立实体进行交互,并在复制、粘贴和编辑时保持完整。CKEditor 5 通过小部件 API允许这样做。如果你想了解如何在elementToStructure()之上使用它,请务必查看实现块小部件教程。

# 属性到元素转换助手

属性到元素转换用于创建格式化视图元素,例如<b><span style="font-family: ...">(我们称之为属性元素)。在这种情况下,我们不转换模型元素,而是转换文本节点的属性。需要注意的是,文本格式,如粗体或字体大小,应该在模型中表示为文本节点属性。

一般来说,模型没有实现“内联元素”的概念(按照 CSS 定义)。内联元素唯一可以使用的场景是自包含对象,例如软换行(<br>)或内联图像。

# 基本文本属性到模型转换

editor.conversion
    .for( 'downcast' )
    .attributeToElement( {
        model: 'bold',
        view: 'strong'
    } );

模型文本节点"CKEditor&nbsp;5"具有bold属性将成为视图中的<strong>"CKEditor&nbsp;5"</strong>

# 使用视图元素定义

你可能希望输出一个具有更多属性的视图元素,例如类名。为了实现这一点,你可以在view属性中提供一个元素定义

editor.conversion
    .for( 'downcast' )
    .attributeToElement( {
        model: 'invert',
        view: {
            name: 'span',
            classes: [ 'font-light', 'bg-dark' ]
        }
    } );

查看ElementDefinition 文档以了解更多详细信息。

# 使用回调创建视图元素

你也可以通过回调生成视图元素。这种方法在视图元素依赖于模型属性的值时很有用。

editor.conversion
    .for( 'downcast' )
    .attributeToElement( {
        model: 'bold',
        view: ( modelAttributeValue, conversionApi ) => {
            const { writer } = conversionApi;

            return writer.createAttributeElement( 'span', {
                style: 'font-weight:' + modelAttributeValue
            } );
        }
    } );

视图回调的第二个参数是DowncastConversionApi对象。它包含许多在编写更复杂的转换器时可能会有用的属性和方法。

# 更改转换器优先级

如果已经存在其他转换器,你可以优先考虑你的转换器来覆盖现有的转换器。为此,请使用converterPriority属性

editor.conversion
    .for( 'downcast' )
    .attributeToElement( {
        model: 'bold',
        view: 'strong'
    } );

editor.conversion
    .for( 'downcast' )
    .attributeToElement( {
        model: 'bold',
        view: 'b',
        converterPriority: 'high'
    } );

在上面的示例中,第一个转换器没有显式设置优先级,因此它假设默认优先级,即normal。第二个转换器通过将优先级设置为high来覆盖它。同时使用这两个转换器将导致bold属性被转换为<b>元素。

# 属性到属性转换助手

attributeToAttribute()助手允许注册处理特定属性并将其转换为视图元素属性的转换器。

通常,在为元素注册转换器时(例如,使用elementToElement()elementToStructure()),你将希望在处理元素本身时处理它们的属性。

attributeToAttribute()助手在出于某种原因你无法在elementToElement()助手内部覆盖特定属性时非常有用。例如,当你在扩展其他人的插件时。

这种类型的转换器助手仅在已经提供元素转换器的情况下才有效。尝试在没有接收视图元素的情况下转换为属性将导致错误。

# 基本属性到属性转换

此转换导致向视图节点添加属性,基于模型节点的属性。例如,<imageInline src='foo.jpg'></imageInline>被转换为<img src='foo.jpg'></img>

editor.conversion
    .for( 'downcast' )
    .attributeToAttribute( {
        model: 'source',
        view: 'src'
    } );

# 转换特定的模型元素和属性

上面的转换器将转换文档中的所有source模型属性。你可以通过提供模型元素名称来限制它的范围。你可以通过以下代码实现

editor.conversion
    .for( 'downcast' )
    .attributeToAttribute( {
        model: {
            name: 'imageInline',
            key: 'source'
        },
        view: 'src'
    } );

此更新后的转换器将只转换imageInline模型元素上存在的source模型属性。

# 从选定的模型值列表创建自定义视图元素

一旦你在model.values属性中提供数组,view属性就应该是一个对象,其键与这些值匹配。使用下面的示例可以更好地解释这一点

editor.conversion
    .for( 'downcast' )
    .attributeToAttribute( {
        model: {
            name: 'styled',
            values: [ 'dark', 'light' ]
        },
        view: {
            dark: {
                key: 'class',
                value: [ 'styled', 'styled-dark' ]
            },
            light: {
                key: 'class',
                value: [ 'styled', 'styled-light' ]
            }
        }
    } );

# 根据模型值创建具有自定义值的视图属性

视图属性的值可以在转换器中修改。以下是一个简单的映射器,它根据模型属性值设置类属性

editor.conversion
    .for( 'downcast' )
    .attributeToAttribute( {
        model: 'styled',
        view: modelAttributeValue => ( {
            key: 'class',
            value: 'styled-' + modelAttributeValue
        } )
    } );

值得注意的是,以这种方式提供样式属性需要返回的 value 为一个对象

editor.conversion
    .for( 'downcast' )
    .attributeToAttribute( {
        model: 'lineHeight',
        view: modelAttributeValue => ( {
            key: 'style',
            value: {
                'line-height': modelAttributeValue,
                'border-bottom': '1px dotted #ba2'
            }
        } )
    } );

# 更改转换器优先级

您可以通过指定更高的优先级来覆盖现有的转换器,例如以下示例

editor.conversion
    .for( 'downcast' )
    .attributeToAttribute( {
        model: 'source',
        view: 'href'
    } );

editor.conversion
    .for( 'downcast' )
    .attributeToAttribute( {
        model: 'source',
        view: 'src',
        converterPriority: 'high'
    } );

第一个转换器具有默认优先级 normal。第二个转换器将被更早调用,因为它具有更高的优先级,因此 source 模型属性将被转换为 src 视图属性而不是 href

# 进一步阅读

查看 专用指南,其中包含完整的互补 上行转换助手 列表。