如何为基于TypeScript的React版CkEditor 5开发自定义插件?
基于TypeScript的React版CKEditor 5 视频导入自定义插件开发步骤
1. 前置环境配置
- 确保项目内所有CKEditor 5相关依赖版本完全一致,避免类型兼容问题
- 安装核心依赖与TS类型包:
npm install @ckeditor/ckeditor5-react @ckeditor/ckeditor5-core @ckeditor/ckeditor5-ui @ckeditor/ckeditor5-utils @types/ckeditor__ckeditor5-core @types/ckeditor__ckeditor5-ui
2. 扩展CKEditor 5 TS类型声明
新建types/ckeditor5-video.d.ts文件,补充自定义插件的类型定义,避免TS编译报错:
import '@ckeditor/ckeditor5-core'; declare module '@ckeditor/ckeditor5-core' { interface EditorConfig { video?: { allowedFileTypes?: string[]; uploadApi?: string; } } interface PluginsMap { [VideoImport.pluginName]: VideoImport; } }
3. 实现视频导入插件核心逻辑
新建plugins/VideoImport.ts文件:
import { Plugin } from '@ckeditor/ckeditor5-core'; import { FileDialogButtonView } from '@ckeditor/ckeditor5-ui'; import { FileRepository } from '@ckeditor/ckeditor5-upload'; export default class VideoImport extends Plugin { public static get pluginName() { return 'VideoImport' as const; } public static get requires() { return [FileRepository] as const; } public init(): void { const editor = this.editor; const t = editor.t; // 注册video标签的schema规则 editor.model.schema.register('video', { allowWhere: 'imageBlock', isObject: true, isBlock: true, allowAttributes: ['src', 'controls', 'width', 'height'] }); // 配置model到视图的转换规则 editor.conversion.for('downcast').elementToElement({ model: 'video', view: (modelElement, { writer }) => { return writer.createEmptyElement('video', { src: modelElement.getAttribute('src') as string, controls: true, width: '100%' }); } }); // 配置视图到model的转换规则 editor.conversion.for('upcast').elementToElement({ view: { name: 'video' }, model: 'video' }); // 注册工具栏按钮 editor.ui.componentFactory.add('videoImport', () => { const button = new FileDialogButtonView(editor.locale); button.set({ label: t('插入视频'), tooltip: true, acceptType: ['video/*'], allowMultipleFiles: false }); button.on('execute', () => { const files = button.fileView.files; if (!files?.length) return; this.handleVideoUpload(files[0]); }); return button; }); } private handleVideoUpload(file: File): void { const editor = this.editor; // 此处替换为你的业务侧视频上传逻辑 const uploadPromise = new Promise<string>((resolve) => { // 示例:模拟上传完成后返回视频在线地址 setTimeout(() => resolve(URL.createObjectURL(file)), 1000); }); uploadPromise.then(videoUrl => { editor.model.change(writer => { const videoNode = writer.createElement('video', { src: videoUrl }); editor.model.insertContent(videoNode, editor.model.document.selection); }); }).catch(err => { console.error('视频上传失败:', err); }); } }
4. 在React组件中引入插件
import { CKEditor } from '@ckeditor/ckeditor5-react'; import ClassicEditor from '@ckeditor/ckeditor5-build-classic'; import VideoImport from './plugins/VideoImport'; const MyEditor = () => { return ( <CKEditor editor={ClassicEditor} config={{ extraPlugins: [VideoImport], toolbar: [ 'heading', 'bold', 'italic', 'videoImport' // 其他工具栏配置项 ] }} onChange={(event, editor) => { console.log(editor.getData()); }} /> ); }; export default MyEditor;
常见问题处理
- 如果出现插件类型不匹配的报错,可以在引入插件时添加
as any临时兼容,后续再补充完整的类型定义即可 - 如果需要支持粘贴视频链接插入的能力,可在上述插件基础上扩展弹窗表单逻辑即可
内容的提问来源于stack exchange,提问作者Milos
相关产品推荐
相关产品推荐

