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; });
关键修复点
- 避免直接操作
toWidget返回对象:toWidget会封装视图元素,需先构建完整元素树,最后再将最外层转为Widget。 - 正确使用Slot:将slot插入可编辑区域内部,确保模型内容能正确映射到编辑视图。
- 外层容器添加交互类:
ck-widget类让CKEditor识别这是Widget组件,提供选中、退出编辑等默认交互。 - 插入默认内容:工具栏插入时添加默认段落,避免空容器引发的错误。
样式优化(可选)
为编辑视图的外层容器添加样式,提升用户识别度:
.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
相关产品推荐
相关产品推荐

