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

CKEditor5块级Widget:如何用elementToStructure实现编辑下转换?

解决方案:单层模型实现CKEditor5可交互块级Widget

核心思路

保持单层模型myList,通过编辑下转换构建带交互的视图结构(外层Widget容器+内部可编辑区域),同时数据下转换直接输出兼容现有标记的单层<div class="my-list">,避免复杂的双层模型映射。

完整代码实现

1. 模型定义(保持原有代码)

schema.register('myList', {
  isLimit: true,
  allowWhere: '$block',
  allowContentOf: '$root',
});

2. 数据转换(确保输出单层结构)

// 数据下转换:模型 -> 数据视图(输出目标单层结构)
conversion.for('dataDowncast').elementToElement({
  model: 'myList',
  view: (modelElement, { writer }) => {
    return writer.createContainerElement('div', { class: 'my-list' });
  }
});

// 数据上转换:数据视图 -> 模型(从现有单层标记解析)
conversion.for('dataUpcast').elementToElement({
  view: {
    name: 'div',
    classes: 'my-list'
  },
  model: 'myList'
});

3. 编辑下转换(构建带交互的编辑视图)

修正之前的错误,正确使用elementToStructure、toWidget和toWidgetEditable:

conversion.for('editingDowncast').elementToStructure({
  model: 'myList',
  view: (modelElement, { writer }) => {
    // 1. 创建内部可编辑区域(对应数据视图的my-list容器)
    const editableDiv = writer.createEditableElement('div', { class: 'my-list' });
    const editableWidget = toWidgetEditable(editableDiv, writer);

    // 2. 创建外层Widget容器(用于提供选中、退出编辑等交互)
    const outerContainer = writer.createContainerElement('div', { 
      class: 'ck-widget my-list__wrapper' 
    });

    // 3. 将可编辑区域插入外层容器
    writer.insert(writer.createPositionAt(outerContainer, 0), editableWidget);

    // 4. 插入slot,让模型内容映射到可编辑区域
    writer.insert(writer.createPositionAt(editableWidget, 0), writer.createSlot());

    // 5. 把外层容器转为Widget,赋予交互能力
    return toWidget(outerContainer, writer, { label: '自定义列表容器' });
  }
});

4. 工具栏按钮注册(确保可正常插入)

editor.ui.componentFactory.add('myList', () => {
  const button = writer.createButton('插入自定义列表', {
    icon: '<svg>...</svg>', // 替换为你的图标代码
    withText: true
  });

  button.on('execute', () => {
    editor.model.change(writer => {
      const myList = writer.createElement('myList');
      // 插入默认段落,避免空容器导致交互异常
      writer.insert(writer.createElement('paragraph'), myList);
      editor.model.insertContent(myList);
      // 自动聚焦到内部可编辑区域
      editor.editing.view.focus();
      writer.setSelection(writer.createPositionAt(myList, 0));
    });
  });

  return button;
});

关键修复点

  1. 避免直接操作toWidget返回对象:toWidget会封装视图元素,需先构建完整元素树,最后再将最外层转为Widget。
  2. 正确使用Slot:将slot插入可编辑区域内部,确保模型内容能正确映射到编辑视图。
  3. 外层容器添加交互类:ck-widget类让CKEditor识别这是Widget组件,提供选中、退出编辑等默认交互。
  4. 插入默认内容:工具栏插入时添加默认段落,避免空容器引发的错误。

样式优化(可选)

为编辑视图的外层容器添加样式,提升用户识别度:

.my-list__wrapper {
  padding: 8px;
  border: 1px dashed #ccc;
  margin: 10px 0;
}
.my-list__wrapper.ck-widget_selected {
  border-color: #1a73e8;
  background: rgba(26, 115, 232, 0.05);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 23:22:53