zoukankan      html  css  js  c++  java
  • CKEditor 5 摸爬滚打(二)—— 自定义一个简单的加粗插件(上)

    基于编辑器做二次开发,可能大部分的工作量都在于自定义插件

    而 CKEditor 5 实现了一套自己的 MVC 架构,导致开发自定义插件尤为复杂

     

    一、插件的基本架构

    CKEditor 5 的自定义插件都需要从 Plugin 类继承,在此基础上根据实际情况开发三个模块:

    1. editing: 插件的核心代码,注册插件对应的 Model,以及插件相关的命令、视图转换等;

    2. ui: 常用的是 ButtonView,用来注册工具栏上的图标按钮;其他需要自定义的视图需要自行编写模板 Template

    3. command: 自定义指令 Command,一般用于工具栏,用来控制工具栏按钮的状态和行为;也可以注册一般命令,只在代码中触发,而不暴露给用户;

     

    这里提到了 Model 这个概念,它是 CKEditor 5 在编辑器中的数据模型

    也就是说,我们在 CKEditor 5 中编辑内容的时候,并不是像常规编辑器那样直接编辑 DOM,而是编辑 Model

    Model 其实就像是 Vue 或者 React 中的模板,每个插件需要创建自己的 schema(类似于组件),组装成类似这样的 Model

    <$root>
      <paragraph>
        <$text>this is text content</$text>
      </paragraph>
      <paragraph>
        <plugin-image src="foo" title="bar"></plugin-image>
      </paragraph>
    </$root>

    然后通过转换器 conversion,在输出的时候将 Model 转换为富文本:

    <p>this is text content</p>
    <p>
      <div class="plugin-image">
        <img src="foo">
        <p class="title">bar</p>
      </div>
    </p>

    这里 plugin-image 的转换结果是瞎写的,在开发的时候需要自行定义转换规则

    需要注意的是,由于 Model 和 conversion 的存在,一切直接操作 DOM 的开发手段都会失效

     

    一下子接收到这些概念可能有点懵,不要慌,接下来用一个加粗插件的简单例子来深入了解

     

    二、添加工具栏图标

    在项目的 packages 目录下创建插件目录 plugin-bold,然后创建以下文件:


    首先是 command.js:

    // command.js
    
    import Command from "@ckeditor/ckeditor5-core/src/command";
    
    export default class BoldCommand extends Command {
      refresh() {
        this.isEnabled = true;
      }
    
      execute() {
        console.log("Execute Plugin-Bold");
      }
    }

    这里的 BoldCommand 对象继承自 CKEditor5-Core 的 Command 类,这个类提供了三个静态属性:

    1. editor: 编辑器实例;

    2. value: 命令的值,有需要时可以手动修改;

    3. isEnabled: 是否启用,命令被禁用时无法触发,一般会关联工具栏中的启用状态。

    另外还有两个钩子函数 refresh() 和 execute()

    refresh 会在编辑器更新的时候执行,类似于 React 中的 render 函数

    execute 是该命令的执行函数,会在命令被触发时执行

    目前只是简单的创建了 BoldCommand 这个子类,具体的逻辑后面再来开发 


    然后编辑 editing.js

    // editing.js
    
    import Plugin from "@ckeditor/ckeditor5-core/src/plugin";
    import BoldCommand from "./command";
    import { COMMAND_NAME__BOLD } from "./constant";
    
    export default class BoldEditing extends Plugin {
      static get pluginName() {
        return "BoldEditing";
      }
      init() {
        const editor = this.editor;
        // 注册一个 BoldCommand 命令
        editor.commands.add(COMMAND_NAME__BOLD, new BoldCommand(editor));
      }
    }

    eidting.js 继承自 Plugin 类,加载的时候会自动执行 init() 方法

    完整的 editing.js 会包含很多内容,这里先只是注册一个 BoldCommand 命令,其他的逻辑后面补充

    在通过 editor.commands.add() 方法注册命令的时候,第一个参数是命令名称,类型为字符串,我放在 constant.js 中单独维护

    // constant.js
    export const COMMAND_NAME__BOLD = 'ck-bold';
    export const COMMAND_LABEL__BOLD = '加粗';

    接下来就是加粗插件在工具栏上的按钮 toolbar-ui.js

    // toolbar-ui.js
    
    import Plugin from "@ckeditor/ckeditor5-core/src/plugin";
    import ButtonView from "@ckeditor/ckeditor5-ui/src/button/buttonview";
    import boldIcon from "@ckeditor/ckeditor5-basic-styles/theme/icons/bold.svg";
    import { COMMAND_NAME__BOLD, COMMAND_LABEL__BOLD } from "./constant";
    
    export default class BoldToolbarUI extends Plugin {
      init() {
        this._createToolbarButton();
      }
    
      _createToolbarButton() {
        const editor = this.editor;
        const command = editor.commands.get(COMMAND_NAME__BOLD);
        editor.ui.componentFactory.add(COMMAND_NAME__BOLD, (locale) => {
          const view = new ButtonView(locale);
          view.set({
            label: COMMAND_LABEL__BOLD,
            tooltip: true,
            icon: boldIcon,
            // withText: true, // 在按钮上展示 label
            class: "toolbar_button_bold",
          });
          // 将按钮的状态关联到命令对应值上
          view.bind("isOn", "isEnabled").to(command, "value", "isEnabled");
          // 点击按钮时触发相应命令
          this.listenTo(view, "execute", () => editor.execute(COMMAND_NAME__BOLD));
          return view;
        });
      }
    }

    这里主要是引入了 ButtonView,并基于此创建了一个按钮实例 view(属性的注释可以参考第一小节的思维导图)

    然后通过 bind() 方法将按钮 view 的 isOn 状态关联到 command 命令的值 value,将 isEnabled 状态关联到命令的 isEnabled

    最终通过 editor.ui.componentFactory.add() 方法创建了一个 UI 组件,该方法的第一个参数是组件名称

    因为没必要创建多余变量,我直接用了命令名称 COMMAND_NAME__BOLD(也可以用别的名称,但也需要单独维护,因为后面还会用到)

    创建 UI 组件之后,就可以在创建组件的时候,通过配置 toolbar 属性(在数组中添加刚才设置的组件名称)将对应的按钮展示到 toolbar 上

    在 toolbar 上展示的按钮,可以通过按钮自身的 isOn 和 isEnabled 状态来高亮和禁用

    另外,BoldToolbarUI 依然是继承自 Plugin 类 

     

    三、在编辑器中引入插件

    插件的三大模块已经搞定,接下来在 main.js 中引入

    // plugin-bold/main.js
    
    import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
    import ToolbarUI from './toolbar-ui';
    import BoldEditing from './editing';
    import { COMMAND_NAME__BOLD } from './constant';
    
    export default class Bold extends Plugin {
      static get requires() {
        return [ BoldEditing, ToolbarUI ];
      }
      static get pluginName() {
       return COMMAND_NAME__BOLD;
      }
    }

    main.js 中的 Bold 也是 Plugin 的子类,这里有一个静态方法 requires,这个方法返回一个由 Plugin 组成的数组,用于加载依赖插件

    到此为止这个插件已经可以用了,在编辑器 packages/my-editor/src/index.js 中注释掉除了 Essentials 和 Paragraph 以外的插件

    并调整 create 函数中的 plugins 和 toolbar 配置项,删除被注释掉的插件

    然后引入自己开发的 plugin-bold 插件

    import Bold from '../../plugin-bold/main';

    后面还会引入更多的自定义插件,所以最好是添加路径别名,可以在根目录的 webpack.config.js 追加配置项:

    resolve: {
      alias: {
        "@plugin": path.resolve("/packages"),
      },
    }

    打包配置文件 packages/my-editor/webpack.config.js 同样需要修改:

    resolve: {
      alias: {
        "@plugin": path.resolve( __dirname, "../"),
      },
    },

    然后就能用别名引入插件了:

    import Bold from "@plugin/plugin-bold/main";

    如果使用 VSCode 无法识别路径,可以在项目的根目录添加一个 jsconfig.json

    {
      "compilerOptions": {
        "baseUrl": "./",
        "paths": {
          "@plugin/*": ["packages/*"]
        }
      },
      "exclude": ["node_modules"]
    }

    回到编辑器文件 packages/my-editor/src/index.js,编辑 ClassicEditor.create() 方法的第二个参数中的 plugins 和 toolbar

    plugins: [ Essentials, Paragraph, Bold ],
    toolbar: [ "undo", "redo", "|", Bold.pluginName ],

    这里 toolbar 中添加的是 toolbar-ui.js 文件中 editor.ui.componentFactory.add() 创建的 UI 组件名

    插件已经引入了,运行 yarn run dev 启动项目,可以看到这样的编辑器:

    点击工具栏上的加粗按钮,控制台会打印 "Execute Plugin-Bold",这说明我们成功地迈出了自定义插件的第一步

    接下来就是最为头疼的部分:model 与 conversion

    to be continue...

  • 相关阅读:
    复习 层叠样式表
    asp后台练习总结
    序列化
    WindowsForm 增 删 查 改
    WindowsForm 计算器
    UML建模和开发预演
    rabbitmq 使用心得
    设计模式之策略模式
    单一职责原则
    设计模式之工厂模式
  • 原文地址:https://www.cnblogs.com/wisewrong/p/14417847.html
Copyright © 2011-2022 走看看