Contribute to this guide

指南通用 HTML 支持

使用通用 HTML 支持 (GHS) 功能,开发者可以启用任何其他专用 CKEditor 5 插件不支持的 HTML 功能。GHS 允许您将元素、属性、类和样式添加到源代码。它还确保此标记保留在编辑器窗口和输出中。

# 演示

使用 源代码编辑功能 工具栏按钮 源代码编辑 查看和编辑文档的 HTML 源代码。您可以在演示下方找到此代码片段的配置。

您可以使用 config.htmlSupport 属性配置通用 HTML 支持功能。使用此属性,您需要列出应由 GHS 处理的 HTML 功能。

HTML 游乐场

此演示展示了一组有限的功能。访问 功能丰富的编辑器示例 以查看更多实际应用。

# 附加功能信息

以下是一些您可以使用通用 HTML 支持启用的 HTML 功能示例

  • <section><article><div> 元素。
  • <audio><video><iframe> 元素。
  • <span><cite> 元素。
  • 现有专用 CKEditor 5 功能上的一些属性
    • 例如 <p><h1-h6> 上的 data-*id 属性。
    • 例如 <strong><a> 上的 styleclasses 属性。

您可以加载(例如,通过 editor.setData())、粘贴、输出(例如,通过 editor.getData())启用的 HTML 功能。它们也可见于编辑区域。在一定程度上,您也可以在编辑器中编辑此类内容。在 支持级别 部分中了解更多信息。

# 支持级别

专用 CKEditor 5 功能(例如 基本样式标题)与 GHS 启用的 HTML 功能之间的区别在于,支持特定 HTML 功能的插件为该功能提供了完整的用户体验。GHS 仅确保编辑器接受此类内容。

例如,专用的 粗体 功能提供了一个工具栏按钮,用于使选定的文本变为粗体。它还与 自动格式化功能 协同工作,允许通过在编辑器中键入 Markdown 快捷代码(**foo**)来将粗体样式应用于内容。 标题 功能提供了一个下拉菜单,用户可以在其中选择标题级别,并确保在标题末尾按 Enter 会创建一个新段落(而不是另一个标题)。

通用 HTML 支持 (GHS) 不会为已启用的功能提供任何用户界面,只考虑给定功能的基本语义。如果您通过 GHS 启用对 `<div>` 元素的支持,用户将无法从编辑器界面创建此类元素。GHS 知道 `<div>` 是一个容器元素,因此它可以包装其他块(如段落),但不能用于内联(例如,与 `<strong>` 元素并排)。在这方面,它类似于 CKEditor 4 中的高级内容过滤 (ACF) 功能,因为它允许您创建一个列表,其中包含编辑器不会去除的标记标签。

因此,GHS 的主要用例是:

  • 确保与旧系统向后兼容内容。
  • 以低成本引入对缺少的 HTML 功能的基本支持。

考虑到 GHS 的性质,您可以考虑同时安装 源代码编辑 功能。

# 安装

⚠️ 新的导入路径

42.0.0 版本 开始,我们更改了导入路径的格式。本指南使用新的、更短的格式。如果您使用的是 CKEditor 5 的旧版本,请参考 旧版设置中的包 指南。

安装编辑器 后,将功能添加到您的插件列表和工具栏配置中。

import { ClassicEditor, GeneralHtmlSupport } from 'ckeditor5';

ClassicEditor
    .create( document.querySelector( '#editor' ), {
        plugins: [ GeneralHtmlSupport, /* ... */ ],
    } )
    .then( /* ... */ )
    .catch( /* ... */ );

# 配置

默认情况下,启用 GeneralHtmlSupport 插件不会为任何给定元素启用支持。您需要通过 config.htmlSupport 选项配置用户想要使用的元素。

ClassicEditor
    .create( document.querySelector( '#editor' ), {
        htmlSupport: {
            allow: [ /* HTML features to allow. */ ],
            disallow: [ /* HTML features to disallow. */ ]
        }
    } )
    .then( /* ... */ )
    .catch( /* ... */ );

allowdisallow 规则的表示法如下:

[
    {
        // The element name to enable or extend with
        // the following styles, classes, and other attributes.
        name: string|regexp,

        // Styles to allow (by name, name and value, or just all).
        styles: object<string=>true|string|regexp>|array<string>|true,

        // Classes to allow (by name or just all).
        classes: array<string|regexp>|true,

        // Other attributes to allow (by name, name and value, or just all).
        attributes: object<string=>true|string|regexp>|array<string>|true,
    }
]

几个实现示例

htmlSupport: {
    allow: [
        // Enables plain <div> elements.
        {
            name: 'div'
        },

        // Enables plain <div>, <section>, and <article> elements.
        {
            name: /^(div|section|article)$/
        },

        // Enables <div> elements with all inline styles (but no other attributes).
        {
            name: 'div',
            styles: true
        },

        // Enables <div> elements with "foo" and "bar" classes.
        {
            name: 'div',
            classes: [ 'foo', 'bar' ]
        },

        // Adds support for "foo" and "bar" classes to the already supported
        // <p> elements (those are enabled by the dedicated paragraph feature).
        {
            name: 'p',
            classes: [ 'foo', 'bar' ]
        },

        // Enables <div> elements with foo="true" attribute and "bar" attribute that
        // can accept any value (the Boolean "true" value works as an asterisk).
        {
            name: 'div',
            attributes: {
                foo: 'true',
                bar: true
            }
        },

        // Adds support for style="color: *" to the already supported
        // <p> and <h2-h4> elements.
        {
            name: /^(p|h[2-4])$/',
            styles: { 'color': true }
        },
}

通用 HTML 支持功能区分了几种内容类型,每种类型处理方式略有不同。

  • 容器元素(如 `<section>`、`<div>`)。
  • 内联元素(如 `<span>`、`<a>`)。
  • 对象元素(如 `<iframe>`、`<video>`)。

启用的元素不会在内容中的“任何位置”可用。它们仍然需要遵循从 HTML 架构和常识得出的某些规则。此外,特定类型元素在编辑区域中的行为将有所不同。例如,对象元素只能作为整体进行选择。内联元素的工作方式与 CKEditor 5 支持的其他格式化功能(如粗体和斜体)相同。

# 启用所有 HTML 功能

有时您可能希望启用所有 HTML 功能,以便编辑器允许所有元素和属性。您可以通过特殊配置来实现这一点。

htmlSupport: {
    allow: [
        {
            name: /.*/,
            attributes: true,
            classes: true,
            styles: true
        }
    ]
}

启用所有 HTML 功能会造成安全风险。您应该将禁止使用的元素和属性列表传递给配置,以确保不会在编辑器中保存和执行任何恶意代码。

此配置的工作方式类似于 CKEditor 4 中的 allowedContent: true 选项。

# 安全

当您将 GHS 设置为允许 `<script>` 等元素或 `onclick` 等属性时,您会将应用程序的用户暴露于可能存在恶意的标记。这可能是从危险网站错误复制的代码,也可能是恶意行为者有意提供的代码。例如:<div onclick="leakUserData()">

默认情况下,编辑器中的内容(您在编辑区域中看到的内容)会过滤掉可能破坏编辑器的典型内容。但是,编辑器没有提供完整的 XSS 过滤器。我们建议您配置 GHS 以启用特定的 HTML 标记,而不是一次启用所有标记。

此外,作为一项通用的规则(并非 GHS 独有),您的应用程序的后端应该始终存在一个消毒过程。即使在您的应用程序的浏览器端完成的最佳过滤也可能被减轻,并且每个网络调用都可能被操纵,从而绕过前端过滤。这很快就会成为安全风险。

除了消毒过程和安全的 GHS 配置之外,强烈建议设置严格的 内容安全策略 规则。

# 启用自定义元素

您可以定义带有属性和类的自定义 HTML 元素。

要使用新元素,您需要使用 DataSchema 将其注册为以下类型之一。

  • 内联元素。
  • 块元素。

要启用此类元素并向其添加属性或类,您需要使用 allowElementallowAttributes 方法,这些方法来自 DataFilter API。

基本实现示例

import { ClassicEditor, Essentials, Paragraph, Plugin, SourceEditing, GeneralHtmlSupport } from 'ckeditor5';

/**
* A plugin extending General HTML Support, for example, with custom HTML elements.
*/
class ExtendHTMLSupport extends Plugin {
    static get requires() {
        return [ GeneralHtmlSupport ];
    }

    init() {
        // Extend the schema with custom HTML elements.
        const dataFilter = this.editor.plugins.get( 'DataFilter' );
        const dataSchema = this.editor.plugins.get( 'DataSchema' );

        // Inline element.
        dataSchema.registerInlineElement( {
            view: 'element-inline',
            model: 'myElementInline'
        } );

        // Custom elements need to be registered using direct API instead of configuration.
        dataFilter.allowElement( 'element-inline' );
        dataFilter.allowAttributes( { name: 'element-inline', attributes: { 'data-foo': false }, classes: [ 'foo' ] } );

        // Block element.
        dataSchema.registerBlockElement( {
            view: 'element-block',
            model: 'myElementBlock',
            modelSchema: {
                inheritAllFrom: '$block'
            }
        } );

        dataFilter.allowElement( 'element-block' );
    }
}

ClassicEditor
    .create( document.querySelector( '#editor' ), {
        plugins: [
            Essentials,
            Paragraph,
            ExtendHTMLSupport
        ],
        htmlSupport: {
            allow: [
                {
                    name: /.*/,
                    attributes: true,
                    classes: true,
                    styles: true
                }
            ]
        }
    } )
    .then( /* ... */ )
    .catch( /* ... */ );

您可以将内联元素和块元素都视为对象元素。要使之成为可能,需要将 isObject 属性设置为 true

// Inline object element.
dataSchema.registerInlineElement( {
    view: 'object-inline',
    model: 'myObjectInline',
    isObject: true,
    modelSchema: {
        inheritAllFrom: '$inlineObject'
    }
} );

dataFilter.allowElement( 'object-inline' );

// Block object element.
dataSchema.registerBlockElement( {
    view: 'object-block',
    model: 'myObjectBlock',
    isObject: true,
    modelSchema: {
        inheritAllFrom: '$blockObject'
    }
} );

dataFilter.allowElement( 'object-block' );

# 已知问题

您可以为现有的 CKEditor 5 功能(如段落、标题、列表项等)添加对任意样式、类和其他属性的支持。大多数现有的 CKEditor 5 功能已经可以通过这种方式扩展,但有些功能尚不可行。这包括列表功能的 `<ul>` 和 `<ol>` 元素(参见:#9917)。

虽然 GHS 功能很稳定,但如果您将其与 实时协作 一起使用,可能会出现与复杂文档相关的问题。

我们欢迎反馈,如果您发现任何问题,请随时在 主要的 CKEditor 5 存储库 中报告。

CKEditor 5 还有其他与 HTML 编辑相关的功能,您可能想要查看这些功能。

  • 完整页面 HTML - 允许使用 CKEditor 5 编辑整个 HTML 页面,从 `<html>` 到 `</html>`,包括页面元数据。
  • 源代码编辑 - 提供查看和编辑文档源代码的能力。
  • HTML 嵌入 - 允许在编辑器中嵌入任意 HTML 代码段。