30分钟上手CKEditor5插件开发:自定义格式刷实战

30分钟上手CKEditor5插件开发:自定义格式刷实战

【免费下载链接】ckeditor5 具有模块化架构、现代集成和协作编辑等功能的强大富文本编辑器框架 【免费下载链接】ckeditor5 项目地址: https://gitcode.com/GitHub_Trending/ck/ckeditor5

你还在为重复设置文本格式浪费时间吗?运营同学频繁调整标题样式时是否总需要逐段操作?本文将带你从零开发一个CKEditor5格式刷插件,30分钟内掌握插件开发全流程,最终实现一键复制粘贴文本样式的高效编辑功能。读完本文你将获得:

  • 插件项目结构的标准化搭建方法
  • 核心命令(Command)与UI组件的开发技巧
  • 本地调试与测试的完整流程
  • 官方文档未公开的实战经验

插件开发环境准备

CKEditor5采用模块化架构,插件开发需要基于其核心API。首先确保本地环境满足以下要求:

环境依赖版本要求官方文档
Node.js≥18.0.0docs/getting-started/setup/
npm/yarn≥8.0.0packages/ckeditor5-core/
TypeScript可选docs/framework/development-tools/

通过以下命令快速初始化开发环境(使用官方脚手架):

git clone https://gitcode.com/GitHub_Trending/ck/ckeditor5.git
cd ckeditor5
npm install

插件项目结构设计

遵循CKEditor5的模块化规范,格式刷插件的标准结构如下:

custom-format-painter/
├── src/
│   ├── formatpaintercommand.ts  // 核心命令逻辑
│   ├── formatpainterui.ts       // 工具栏按钮组件
│   ├── formatpainter.ts         // 插件入口
│   └── index.ts                 // 模块导出
├── theme/
│   └── icons/
│       └── format-painter.svg   // 工具栏图标
├── package.json                 // 包配置
└── tsconfig.json                // TypeScript配置

上述结构参考了packages/ckeditor5-basic-styles/的实现方式,这是官方基础样式插件的标准结构。

核心命令实现

样式复制逻辑

格式刷功能分为"复制样式"和"应用样式"两个阶段。首先创建FormatPainterCommand类,继承自CKEditor5的Command基类:

import { Command } from 'ckeditor5/src/core';

export class FormatPainterCommand extends Command {
  private copiedAttributes: Record<string, any> = {};

  // 复制选中元素的样式属性
  execute(action: 'copy' | 'apply') {
    if (action === 'copy') {
      this.copiedAttributes = this._getSelectedAttributes();
      this.editor.model.change(writer => {
        // 视觉反馈:闪烁选中元素
        this._highlightSelection(writer);
      });
    } else if (action === 'apply' && Object.keys(this.copiedAttributes).length) {
      this._applyAttributesToSelection();
    }
  }

  // 获取选中元素的样式属性
  private _getSelectedAttributes() {
    const selection = this.editor.model.document.selection;
    const firstElement = selection.getSelectedElement();
    if (!firstElement) return {};
    
    return {
      fontSize: firstElement.getAttribute('fontSize'),
      fontWeight: firstElement.getAttribute('fontWeight'),
      color: firstElement.getAttribute('color'),
      // 更多样式属性...
    };
  }
}

样式应用逻辑

在命令类中添加应用样式的实现,需处理文本节点和块级元素的不同场景:

private _applyAttributesToSelection() {
  const editor = this.editor;
  const model = editor.model;
  const selection = model.document.selection;

  model.change(writer => {
    for (const range of selection.getRanges()) {
      for (const item of range.getItems()) {
        if (item.is('element')) {
          Object.entries(this.copiedAttributes).forEach(([key, value]) => {
            writer.setAttribute(key, value, item);
          });
        }
      }
    }
  });
}

UI组件开发

工具栏按钮创建

创建FormatPainterUI类,负责注册工具栏按钮和图标:

import { ButtonView, View } from 'ckeditor5/src/ui';
import { Plugin } from 'ckeditor5/src/core';
import formatPainterIcon from '../theme/icons/format-painter.svg';

export class FormatPainterUI extends Plugin {
  init() {
    const editor = this.editor;
    const t = editor.t;
    
    // 注册按钮
    editor.ui.componentFactory.add('formatPainter', locale => {
      const view = new ButtonView(locale);
      const command = editor.commands.get('formatPainter')!;

      view.set({
        label: t('格式刷'),
        icon: formatPainterIcon,
        tooltip: true,
        isToggleable: true
      });

      // 绑定命令状态与按钮状态
      view.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');
      
      // 点击事件:首次点击复制,再次点击应用
      this.listenTo(view, 'execute', () => {
        const action = command.value ? 'apply' : 'copy';
        editor.execute('formatPainter', action);
      });

      return view;
    });
  }
}

图标资源处理

格式刷图标可使用官方图标库生成,放置在theme/icons/format-painter.svg。推荐使用docs/tutorials/creating-simple-plugin-timestamp.md中介绍的SVG优化工具处理图标文件。

插件集成与测试

插件入口文件

创建formatpainter.ts作为插件入口,整合命令与UI:

import { Plugin } from 'ckeditor5/src/core';
import { FormatPainterCommand } from './formatpaintercommand';
import { FormatPainterUI } from './formatpainterui';

export default class FormatPainter extends Plugin {
  static get requires() {
    return [FormatPainterUI] as const;
  }

  static get pluginName() {
    return 'FormatPainter' as const;
  }

  init() {
    const editor = this.editor;
    // 注册命令
    editor.commands.add('formatPainter', new FormatPainterCommand(editor));
  }
}

本地测试配置

修改packages/ckeditor5-editor-classic/src/classiceditor.ts,添加自定义插件:

import FormatPainter from 'custom-format-painter';

ClassicEditor.builtinPlugins = [
  // ...其他插件
  FormatPainter
];

ClassicEditor.defaultConfig = {
  toolbar: {
    items: [
      // ...其他按钮
      'formatPainter'
    ]
  }
};

运行本地开发服务器测试效果:

npm run start -- --files=packages/ckeditor5-editor-classic/src/classiceditor.ts

实战优化技巧

样式过滤机制

为避免复制无效样式,可实现属性过滤白名单:

// 仅复制这些样式属性
const ALLOWED_ATTRIBUTES = ['fontSize', 'fontWeight', 'color', 'textAlign'];

private _getSelectedAttributes() {
  // ...
  return Object.fromEntries(
    Object.entries(attributes)
      .filter(([key]) => ALLOWED_ATTRIBUTES.includes(key))
  );
}

状态持久化

使用LocalStorage保存复制的样式,实现跨编辑器实例共享:

// 保存到本地存储
localStorage.setItem('ckeditor5-format-painter', JSON.stringify(attributes));

// 读取样式
const saved = localStorage.getItem('ckeditor5-format-painter');
if (saved) this.copiedAttributes = JSON.parse(saved);

官方资源与扩展学习

建议后续深入学习"自定义schema定义"和"富文本模型(Model)"概念,这些是实现复杂插件的基础。通过本文方法开发的插件可发布到npm,或集成到docs/examples/custom/展示页面。

CKEditor5架构图

上图展示了CKEditor5的核心架构,插件系统基于此实现松耦合扩展。完整架构说明见docs/framework/architecture/

【免费下载链接】ckeditor5 具有模块化架构、现代集成和协作编辑等功能的强大富文本编辑器框架 【免费下载链接】ckeditor5 项目地址: https://gitcode.com/GitHub_Trending/ck/ckeditor5

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值