You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CKEditor 5中如何实现CKEditor 4自定义内联插件的属性编辑功能?

CKEditor 5 自定义内联Widget迁移方案:优雅更新与回车键拦截

一、优雅更新Widget内容

CKEditor 5 基于模型-视图分离架构,直接替换HTML属于反模式,正确做法是通过修改模型数据实现视图自动同步:

1. 先确保Widget的模型与视图配置正确

首先要给自定义Widget注册模型Schema,并配置双向转换器:

// 1. 注册模型元素
editor.model.schema.register('myWidget', {
  inheritAllFrom: '$inlineObject', // 内联Widget用这个,块级用$blockObject
  allowAttributes: ['data-id', 'content', 'custom-prop'] // 定义需要的属性
});

// 2. 模型→视图转换(渲染)
editor.conversion.for('downcast').elementToElement({
  model: 'myWidget',
  view: (modelEl, { writer: viewWriter }) => {
    const widgetView = viewWriter.createInlineElement('span', {
      class: 'my-inline-widget',
      'data-id': modelEl.getAttribute('data-id')
    });
    // 插入Widget内部内容
    viewWriter.insert(
      viewWriter.createPositionAt(widgetView, 0),
      viewWriter.createText(modelEl.getAttribute('content'))
    );
    return toWidget(widgetView, viewWriter);
  }
});

// 3. 视图→模型转换(比如粘贴时识别)
editor.conversion.for('upcast').elementToElement({
  view: {
    name: 'span',
    classes: 'my-inline-widget'
  },
  model: (viewEl, { writer: modelWriter }) => {
    return modelWriter.createElement('myWidget', {
      'data-id': viewEl.getAttribute('data-id'),
      'content': viewEl.getChild(0).data
    });
  }
});

2. 修改Widget属性/内容的正确姿势

当用户在弹窗中修改完属性后,直接操作模型元素,编辑器会自动更新视图:

// 示例:打开弹窗并更新Widget
function openWidgetSettingsDialog(modelElement) {
  // 用你的jQuery弹窗获取新属性(比如newId、newContent)
  const newId = prompt('输入新ID');
  const newContent = prompt('输入新内容');

  if (newId && newContent) {
    editor.model.change(writer => {
      // 更新属性
      writer.setAttribute('data-id', newId, modelElement);
      writer.setAttribute('content', newContent, modelElement);
      
      // 如果需要修改内部子节点(比如复杂结构)
      // writer.remove(modelElement.getChildren());
      // writer.appendElement('paragraph', {}, modelElement);
    });
  }
}

二、拦截回车键触发自定义操作

通过CKEditor 5的keystrokes API拦截回车键,判断选中的是Widget后触发自定义逻辑并阻止默认行为:

editor.keystrokes.set('Enter', (data, cancel) => {
  const selectedEl = editor.model.document.selection.getSelectedElement();
  // 检查选中的是自定义Widget
  if (selectedEl && selectedEl.is('element', 'myWidget')) {
    openWidgetSettingsDialog(selectedEl); // 调用弹窗函数
    cancel(); // 阻止默认的插入换行/删除Widget行为
  }
});

三、双击事件的正确处理

监听视图层的双击事件,映射到模型元素后触发弹窗:

editor.editing.view.document.on('dblclick', (evt, data) => {
  const viewEl = data.target;
  const modelEl = editor.editing.mapper.toModelElement(viewEl);
  
  if (modelEl && modelEl.is('element', 'myWidget')) {
    openWidgetSettingsDialog(modelEl);
    data.preventDefault(); // 阻止默认双击行为
  }
});

内容的提问来源于stack exchange,提问作者tribalDev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 03:37:33