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

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;
}

代码说明:

  1. instanceReady事件确保编辑器完全初始化后绑定键盘监听;
  2. 拦截上下方向键后,通过选区的公共祖先节点定位当前位置;
  3. 辅助函数findAdjacentWidget按文档流排序所有小部件,找到当前位置的前后相邻小部件;
  4. 找到目标小部件后,阻止默认行为并调用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元素正确获取焦点。

组合方案建议

将两种方案结合使用:

  1. 用方案二优化小部件的结构与无障碍属性;
  2. 用方案一的键盘事件监听处理精确的上下导航逻辑,覆盖编辑器默认行为的不足。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 22:23:12