Angular 富文本编辑器组件
Angular 是一个基于 TypeScript 的开源单页面 Web 应用程序框架。CKEditor 5 的 Angular 组件支持集成不同的编辑器类型。
从该包的 6.0.0 版本开始,您可以使用 CKEditor 5 提供的原生类型定义。查看有关 TypeScript 支持 的详细信息。
# 支持的 Angular 版本
由于 Angular 库输出格式的重大更改,@ckeditor/ckeditor5-angular
包以以下版本发布,以支持各种 Angular 生态系统。
CKEditor 5 Angular 组件版本 | Angular 版本 | 详细信息 |
---|---|---|
积极支持的版本 | ||
^9 |
16+ |
迁移到 TypeScript 5。声明文件不向后兼容。需要 CKEditor 5 版本 43 或更高版本。 |
过去版本(不再维护) | ||
^8 |
13+ |
需要 CKEditor 5 版本 42 或更高版本。 |
^7 |
13+ |
对等依赖项的更改 (问题)。需要 CKEditor 5 版本 37 或更高版本。 |
^6 |
13+ |
需要 CKEditor 5 版本 37 或更高版本。 |
^5 |
13+ |
需要 Angular 版本 13+ 或更高版本。不再维护较低版本。 |
^5 |
13+ |
需要 Angular 版本 13+ 或更高版本。不再维护较低版本。 |
^4 |
9.1+ |
需要 CKEditor 5 版本 34 或更高版本。 |
^3 |
9.1+ |
需要 Node.js 版本 14 或更高版本。 |
^2 |
9.1+ |
迁移到 TypeScript 4。声明文件不向后兼容。 |
^1 |
5.x - 8.x |
不再维护的 Angular 版本。 |
所有可用的 Angular 版本都 列在 npm 上,您可以在其中提取它们。
CKEditor 5 构建器
在我们的交互式构建器中,您可以快速体验 CKEditor 5。它提供了一个易于使用的用户界面,可帮助您配置、预览和下载适合您需求的编辑器。您可以轻松选择
- 编辑器类型。
- 您需要的功能。
- 首选框架 (React、Angular、Vue 或 Vanilla JS)。
- 首选分发方法。
最后,您将获得适合您需求的即用型代码!
# 快速入门
# 设置项目
本指南假设您已经拥有一个 Angular 项目。要创建这样的项目,您可以使用 Angular CLI。请参考 Angular 文档 了解更多信息。
# 从 npm 安装
首先,安装 CKEditor 5 包
ckeditor5
- 包含开源插件和功能的包。ckeditor5-premium-features
- 包含高级插件和功能的包。
根据您的配置和选择的插件,您可能需要安装第一个包或两个包。
npm install ckeditor5 ckeditor5-premium-features
然后,安装 适用于 Angular 的 CKEditor 5 WYSIWYG 编辑器组件
npm install @ckeditor/ckeditor5-angular
以下设置因您使用的组件类型而异。
# 独立组件
独立组件提供了一种简化的方式来构建 Angular 应用程序。它们在 Angular 17 中默认启用。独立组件旨在简化设置并减少对 NGModules
的需求。这就是为什么在这种情况下您不需要这样的模块的原因。
相反,将 CKEditorModule
添加到应用程序组件中的导入中。该组件需要将 standalone
选项设置为 true
。下面的示例显示了如何在使用开源和高级插件的情况下使用该组件。
// app.component.ts
import { Component, ViewEncapsulation } from '@angular/core';
import { CKEditorModule } from '@ckeditor/ckeditor5-angular';
import { ClassicEditor, Bold, Essentials, Italic, Mention, Paragraph, Undo } from 'ckeditor5';
import { SlashCommand } from 'ckeditor5-premium-features';
@Component( {
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
encapsulation: ViewEncapsulation.None,
imports: [ CKEditorModule ],
standalone: true
} )
export class AppComponent {
title = 'angular';
public Editor = ClassicEditor;
public config = {
toolbar: [ 'undo', 'redo', '|', 'bold', 'italic' ],
plugins: [
Bold, Essentials, Italic, Mention, Paragraph, SlashCommand, Undo
],
licenseKey: '<YOUR_LICENSE_KEY>',
// mention: {
// Mention configuration
// }
}
}
根据所使用的插件(仅开源或也包括高级插件),您可能需要导入第一个 CSS 文件或两个 CSS 文件。Angular 默认将样式限定到特定组件。因此,编辑器可能无法检测到附加的样式。您必须将封装选项设置为 ViewEncapsulation.None
以关闭此限定。
/* app.component.css */
@import 'ckeditor5/ckeditor5.css';
@import 'ckeditor5-premium-features/ckeditor5-premium-features.css';
然后,在模板中使用 <ckeditor>
标签运行富文本编辑器
<!-- app.component.html -->
<ckeditor [editor]="Editor" [config]="config" data="<p>Hello, world!</p>"></ckeditor>
# NGModule 组件
如果您想使用 NGModule 组件,请将 CKEditorModule
添加到 imports
数组中。它将使 CKEditor 5 组件在您的 Angular 应用程序中可用。
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { CKEditorModule } from '@ckeditor/ckeditor5-angular';
import { AppComponent } from './app.component';
@NgModule( {
declarations: [
AppComponent
],
imports: [
BrowserModule,
CKEditorModule
],
providers: [],
bootstrap: [ AppComponent ]
} )
export class AppModule { }
然后,在您的 Angular 组件中导入编辑器,并将其分配给一个 public
属性,使其从模板中访问。
// app.component.ts
import { Component, ViewEncapsulation } from '@angular/core';
import { ClassicEditor, Bold, Essentials, Italic, Mention, Paragraph, Undo } from 'ckeditor5';
import { SlashCommand } from 'ckeditor5-premium-features';
@Component( {
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ],
encapsulation: ViewEncapsulation.None
} )
export class AppComponent {
title = 'angular';
public Editor = ClassicEditor;
public config = {
toolbar: [ 'undo', 'redo', '|', 'bold', 'italic' ],
plugins: [
Bold, Essentials, Italic, Mention, Paragraph, SlashCommand, Undo
],
licenseKey: '<YOUR_LICENSE_KEY>',
// mention: {
// Mention configuration
// }
}
}
根据您使用的插件,您可能需要导入第一个 CSS 文件或两个 CSS 文件。Angular 默认将样式限定到特定组件。因此,编辑器可能无法检测到附加的样式。您必须将封装选项设置为 ViewEncapsulation.None
以关闭此限定。
/* app.component.css */
@import 'ckeditor5/ckeditor5.css';
@import 'ckeditor5-premium-features/ckeditor5-premium-features.css';
最后,在模板中使用 <ckeditor>
标签运行富文本编辑器
<!-- app.component.html -->
<ckeditor [editor]="Editor" [config]="config" data="<p>Hello, world!</p>"></ckeditor>
# 支持的 @Input
属性
CKEditor 5 适用于 Angular 的富文本编辑器组件支持以下 @Input
属性
# editor
(必填)
提供静态 Editor
create()
方法来创建编辑器实例
<ckeditor [editor]="Editor"></ckeditor>
# config
编辑器的 配置
<ckeditor [config]="{ toolbar: [ 'heading', '|', 'bold', 'italic' ] }"></ckeditor>
# data
编辑器的初始数据。它可以是一个静态值
<ckeditor data="<p>Hello, world!</p>"></ckeditor>
或一个共享的父组件的属性
@Component( {
// ...
} )
export class MyComponent {
public editorData = '<p>Hello, world!</p>';
// ...
}
<ckeditor [data]="editorData"></ckeditor>
# tagName
将创建富文本编辑器的 HTML 元素的标签名称。
默认标签是 <div>
。
<ckeditor tagName="textarea"></ckeditor>
# disabled
控制编辑器的 只读 状态
@Component( {
// ...
} )
export class MyComponent {
public isDisabled = false;
// ...
toggleDisabled() {
this.isDisabled = !this.isDisabled
}
}
<ckeditor [disabled]="isDisabled"></ckeditor>
<button (click)="toggleDisabled()">
{{ isDisabled ? 'Enable editor' : 'Disable editor' }}
</button>
# watchdog
一个 ContextWatchdog
类的实例,它负责为多个编辑器实例提供相同的上下文,并在发生崩溃时重新启动整个结构。
import CKSource from 'path/to/custom/build';
const Context = CKSource.Context;
const Editor = CKSource.Editor;
const ContextWatchdog = CKSource.ContextWatchdog;
@Component( {
// ...
} )
export class MyComponent {
public editor = Editor;
public watchdog: any;
public ready = false;
ngOnInit() {
const contextConfig = {};
this.watchdog = new ContextWatchdog( Context );
this.watchdog.create( contextConfig )
.then( () => {
this.ready = true;
} );
}
}
<div *ngIf="ready">
<ckeditor [watchdog]="watchdog"></ckeditor>
<ckeditor [watchdog]="watchdog"></ckeditor>
<ckeditor [watchdog]="watchdog"></ckeditor>
</div>
# editorWatchdogConfig
如果未使用 watchdog
属性,则默认情况下将使用 EditorWatchdog
。editorWatchdogConfig
属性允许将 配置 传递给该看门狗。
@Component( {
// ...
} )
export class MyComponent {
public myWatchdogConfig = {
crashNumberLimit: 5,
// ...
};
// ...
}
<ckeditor [editorWatchdogConfig]="myWatchdogConfig"></ckeditor>
# disableTwoWayDataBinding
允许禁用双向数据绑定机制。默认值为 false
。
引入此选项的原因是在大型文档中存在性能问题。默认情况下,在使用 ngModel
指令时,无论何时编辑器的
此选项允许集成者禁用默认行为,并且仅在需要时调用 editor.getData()
# 支持的 @Output
属性
CKEditor 5 适用于 Angular 的富文本编辑器组件支持以下 @Output
属性
# ready
编辑器准备就绪时触发。它对应于 editor#ready
它与编辑器实例一起触发。
请注意,此方法可能会被调用多次。除了初始化之外,它还会在编辑器在崩溃后重新启动时调用。不要在内部保留对编辑器实例的引用,因为它会在重新启动时更改。相反,您应该使用 watchdog.editor
# change
当编辑器的内容发生改变时触发。它对应于 editor.model.document#change:data
事件。
它被触发时,会传递一个包含编辑器和 CKEditor 5 change:data
事件对象的物件。
<ckeditor [editor]="Editor" (change)="onChange($event)"></ckeditor>
import { ClassicEditor } from 'ckeditor5';
import { ChangeEvent } from '@ckeditor/ckeditor5-angular/ckeditor.component';
@Component( {
// ...
} )
export class MyComponent {
public Editor = ClassicEditor;
public onChange( { editor }: ChangeEvent ) {
const data = editor.getData();
console.log( data );
}
// ...
}
# blur
当编辑器视图失去焦点时触发。它对应于 editor.editing.view.document#blur
事件。
它被触发时,会传递一个包含编辑器和 CKEditor 5 blur
事件数据的物件。
# focus
当编辑器视图获得焦点时触发。它对应于 editor.editing.view.document#focus
事件。
它被触发时,会传递一个包含编辑器和 CKEditor 5 focus
事件数据的物件。
# error
当编辑器崩溃时触发。一旦编辑器崩溃,内部的看门狗机制会重启编辑器并触发 ready 事件。
在 ckeditor5-angular v7.0.1
之前,编辑器初始化期间发生的崩溃不会触发此事件。
# 与 ngModel
集成
该组件实现了 ControlValueAccessor
接口,可以与 ngModel
一起使用。以下是使用方法:
在你的组件中创建一些模型,以供编辑器共享。
@Component( {
// ...
} )
export class MyComponent {
public model = {
editorData: '<p>Hello, world!</p>'
};
// ...
}
在模板中使用模型,以启用双向数据绑定。
<ckeditor [(ngModel)]="model.editorData" [editor]="Editor"></ckeditor>
# 样式
用于 Angular 的 CKEditor 5 富文本编辑器组件可以使用组件样式表或全局样式表进行样式化。请参阅如何使用这两种方法设置 CKEditor 5 组件的高度。
# 通过组件样式表设置高度
首先,在父组件的目录中创建一个 (S)CSS 文件,并使用 :host
和 ::ng-deep
伪选择器对给定的编辑器部分进行样式化。
/* src/app/app.component.css */
:host ::ng-deep .ck-editor__editable_inline {
min-height: 500px;
}
然后,在父组件中添加上述样式表的相对路径。
/* src/app/app.component.ts */
@Component( {
// ...
styleUrls: [ './app.component.css' ]
} )
# 通过全局样式表设置高度
要使用全局样式表对组件进行样式化,首先创建一个全局样式表。
/* src/styles.css */
.ck-editor__editable_inline {
min-height: 500px;
}
然后,在 angular.json
配置文件中添加它。
"architect": {
"build": {
"options": {
"styles": [
{ "input": "src/styles.css" }
]
}
}
}
# 设置占位符
要在主可编辑元素中显示 占位符,请在 CKEditor 5 富文本编辑器组件配置中设置 placeholder
字段。
@Component( {
// ...
} )
export class MyComponent {
public config = {
placeholder: 'Type the content here!'
}
}
# 访问编辑器实例
CKEditor 5 富文本编辑器组件提供了满足大多数用例所需的功能。当需要访问完整的 CKEditor 5 API 时,可以通过一个额外的步骤来获取编辑器实例。
为此,创建一个指向 <ckeditor>
组件的模板引用变量 #editor
。
<ckeditor #editor [editor]="Editor"></ckeditor>
然后,使用 @ViewChild( 'editor' )
装饰的属性获取 <ckeditor>
组件,并在需要时访问编辑器实例。
@Component()
export class MyComponent {
@ViewChild( 'editor' ) editorComponent: CKEditorComponent;
public getEditor() {
// Warning: This may return "undefined" if the editor is hidden behind the `*ngIf` directive or
// if the editor is not fully initialised yet.
return this.editorComponent.editorInstance;
}
}
编辑器的创建是异步的,因此 editorInstance
只有在编辑器创建完成后才会可用。如果你想对刚创建的编辑器进行更改,更好的选择是在 ready
事件中获取 CKEditor 5 实例。
# 如何?
# 使用文档编辑器类型
如果你想使用 文档(解耦)编辑器,你需要 手动将工具栏添加到 DOM
// app.component.ts
import { Component, ViewEncapsulation } from '@angular/core';
import { CKEditorModule } from '@ckeditor/ckeditor5-angular';
import { DecoupledEditor, Essentials, Italic, Paragraph, Bold, Undo } from 'ckeditor5';
@Component( {
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ],
encapsulation: ViewEncapsulation.None
imports: [ CKEditorModule ],
standalone: true
} )
export class AppComponent {
title = 'angular';
public Editor = DecoupledEditor;
public config = {
plugins: [ Bold, Essentials, Italic, Paragraph, Undo ],
toolbar: [ 'undo', 'redo', '|', 'bold', 'italic' ]
}
public onReady( editor: DecoupledEditor ): void {
const element = editor.ui.getEditableElement()!;
const parent = element.parentElement!;
parent.insertBefore(
editor.ui.view.toolbar.element!,
element
);
}
}
导入所需的 CSS 样式表。
/* app.component.css */
@import 'ckeditor5/ckeditor5.css';
然后,在模板中链接该方法。
<!-- app.component.html -->
<ckeditor [editor]="Editor" data="<p>Hello, world!</p>" (ready)="onReady($event)"></ckeditor>
# 使用带有协作插件的编辑器
我们提供了一些在 Angular 应用程序中使用协作编辑的即用型集成
并非必须在上述示例的基础上构建应用程序,但它们可以帮助你入门。
# 本地化
CKEditor 5 支持多种 UI 语言,官方的 Angular 组件也是如此。请按照以下说明在你的 Angular 应用程序中翻译 CKEditor 5。
与 CSS 样式表类似,这两个软件包都有单独的翻译。请按照以下示例导入它们。然后,将它们传递给 config
属性的 translations
数组。
// app.component.ts
import { Component, ViewEncapsulation } from '@angular/core';
import { CKEditorModule } from '@ckeditor/ckeditor5-angular';
import { ClassicEditor } from 'ckeditor5';
// More imports...
import coreTranslations from 'ckeditor5/translations/es.js';
import premiumFeaturesTranslations from 'ckeditor5-premium-features/translations/es.js';
@Component( {
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ],
encapsulation: ViewEncapsulation.None
imports: [ CKEditorModule ],
standalone: true
} )
export class AppComponent {
title = 'angular';
public Editor = ClassicEditor;
public config = {
translations: [ coreTranslations, premiumFeaturesTranslations ],
// More configuration options...
}
}
有关高级用法,请参阅 设置 UI 语言 指南。
Angular 17 中的本地化存在一个已知问题。请参阅下面的 已知问题部分 了解详情。
# 已知问题
# 模块解析
TypeScript 配置的 moduleResolution
选项决定了从 node_modules
中查找和解析模块的算法。在 Angular 17 中,该选项默认设置为 node
。此选项会阻止正确加载编辑器翻译的类型声明。要解决此问题,你可以采取以下几种方法:
- 你可以将
moduleResolution
选项设置为bundler
。这是 TypeScript 5.0+ 中针对使用打包器的应用程序的推荐设置。这也是解决此问题的推荐方法。你可以查看下面的其他解决方案,以了解较低版本的 TypeScript。 - 你可以使用
// @ts-expect-error
注释在导入的翻译上方告诉 TypeScript 编译器抑制此问题。 - 你可以将 Angular 更新到版本 18,其中
moduleResolution
选项默认设置为bundler
。 - 你可以直接从我们的 CDN 导入翻译,例如:
import ‘https://cdn.ckeditor.com/ckeditor5/43.3.0/translations/es.umd.js’;
。这样,编辑器会自动加载翻译,因此你无需手动将它们传递到配置中。
# Jest 测试
你可以在 Angular 应用程序中使用 Jest 作为测试运行器。不幸的是,Jest 不使用真实的浏览器。相反,它在 Node.js 中运行测试,该测试使用 JSDOM。JSDOM 不是完整的 DOM 实现,虽然它足以满足标准应用程序,但它无法模拟 CKEditor 5 所需的所有 DOM API。
对于测试 CKEditor 5,建议使用利用真实浏览器并提供完整 DOM 实现的测试框架。一些流行的选择包括:
这些框架为测试 CKEditor 5 提供了更好的支持,并更准确地反映了编辑器在真实浏览器环境中的行为。
如果这是不可能的,并且你仍然想使用 Jest,你可以模拟一些所需的 API。以下是如何模拟 CKEditor 5 使用的一些 API 的示例:
beforeAll( () => {
window.scrollTo = jest.fn();
window.ResizeObserver = class ResizeObserver {
observe() {}
unobserve() {}
disconnect() {}
};
for ( const key of [ 'InputEvent', 'KeyboardEvent' ] ) {
window[ key ].prototype.getTargetRanges = () => {
const range = new StaticRange( {
startContainer: document.body.querySelector( '.ck-editor__editable p' ),
startOffset: 0,
endContainer: document.body.querySelector( '.ck-editor__editable p' ),
endOffset: 0
} );
return [ range ];
};
}
Range.prototype.getClientRects = () => ( {
item: () => null,
length: 0,
[ Symbol.iterator ]: function* () {}
} );
} );
这些模拟应该放在使用 CKEditor 5 的测试之前。它们并不完美,可能无法涵盖所有情况,但它们应该足以满足基本初始化和渲染编辑器。请记住,它们不能替代真正的浏览器测试。
# 贡献和报告问题
用于 Angular 的 CKEditor 5 富文本编辑器组件的源代码在 GitHub 上的 https://github.com/ckeditor/ckeditor5-angular 中提供。
我们每天都在努力使我们的文档保持完整。你是否发现了过时的信息?是否缺少了什么?请通过我们的 问题追踪器 报告它。
随着 42.0.0 版本的发布,我们重新编写了许多文档,以反映新的导入路径和功能。我们感谢你的反馈,帮助我们确保文档的准确性和完整性。