CKEditor 4:如何通过上下方向键聚焦小部件?
在CKEditor 4中通过上下方向键聚焦小部件的可行方案
要解决CKEditor 4中仅支持左右方向键聚焦小部件的无障碍问题,可通过自定义键盘事件拦截结合小部件导航逻辑扩展实现,以下是具体实现步骤:
方案一:自定义键盘事件监听,拦截上下方向键导航
通过监听编辑器的key事件,拦截上下方向键(代码38为上,40为下),判断当前光标位置附近的小部件实例,主动触发聚焦操作:
CKEDITOR.on('instanceReady', function(evt) { const editor = evt.editor; editor.on('key', function(e) { const keyCode = e.data.keyCode; // 仅处理上下方向键 if (keyCode !== 38 && keyCode !== 40) return; const selection = editor.getSelection(); const range = selection.getRanges()[0]; const currentContainer = range.getCommonAncestor(); let targetWidget; if (keyCode === 38) { // 向上查找前一个小部件 targetWidget = findAdjacentWidget(editor, currentContainer, 'prev'); } else { // 向下查找后一个小部件 targetWidget = findAdjacentWidget(editor, currentContainer, 'next'); } if (targetWidget) { // 阻止默认上下键行为,聚焦到目标小部件 e.data.preventDefault(); targetWidget.focus(); } }); }); // 辅助函数:查找相邻的小部件实例 function findAdjacentWidget(editor, startNode, direction) { const widgetInstances = editor.widgets.instances; const widgetNodes = []; // 收集所有小部件的DOM节点及实例 Object.values(widgetInstances).forEach(widget => { widgetNodes.push({ node: widget.element.$, widget: widget }); }); // 按文档流顺序排序小部件 widgetNodes.sort((a, b) => { const position = editor.document.$.compareDocumentPosition(a.node, b.node); return position & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1; }); // 找到当前节点对应的小部件索引 const currentIndex = widgetNodes.findIndex(item => { return startNode.contains(item.node) || item.node.contains(startNode); }); // 根据方向返回相邻小部件 if (direction === 'prev' && currentIndex > 0) { return widgetNodes[currentIndex - 1].widget; } if (direction === 'next' && currentIndex !== -1 && currentIndex < widgetNodes.length - 1) { return widgetNodes[currentIndex + 1].widget; } return null; }
代码说明:
instanceReady事件确保编辑器完全初始化后绑定键盘监听;- 拦截上下方向键后,通过选区的公共祖先节点定位当前位置;
- 辅助函数
findAdjacentWidget按文档流排序所有小部件,找到当前位置的前后相邻小部件; - 找到目标小部件后,阻止默认行为并调用
widget.focus()完成聚焦。
方案二:优化小部件DOM结构与无障碍属性
如果小部件默认是行内元素,编辑器的上下方向键导航可能会忽略它,可将小部件改为块级元素,同时添加无障碍属性提升屏幕阅读器兼容性:
CKEDITOR.plugins.add('customWidget', { requires: 'widget', init: function(editor) { editor.widgets.add('customWidget', { // 使用div作为块级容器 template: '<div class="custom-widget" role="region" aria-label="自定义小部件">小部件内容</div>', allowedContent: 'div(!custom-widget)[role,aria-label]', // 自定义聚焦逻辑,确保屏幕阅读器感知 focus: function() { this.element.$.focus(); // 可选:添加焦点样式,提升视觉反馈 this.element.addClass('widget-focused'); }, blur: function() { this.element.removeClass('widget-focused'); } }); } });
说明:
- 将小部件外层改为
div块级元素,让编辑器默认的上下导航逻辑更容易识别; - 添加
role="region"和aria-label属性,帮助屏幕阅读器识别小部件的用途; - 自定义
focus/blur方法,添加视觉焦点反馈,同时确保DOM元素正确获取焦点。
组合方案建议
将两种方案结合使用:
- 用方案二优化小部件的结构与无障碍属性;
- 用方案一的键盘事件监听处理精确的上下导航逻辑,覆盖编辑器默认行为的不足。
内容的提问来源于stack exchange,提问作者Daniel Costa
相关产品推荐
相关产品推荐

