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

可编辑div输入回车后无法选中对应代码块问题求助

解决可编辑Div中选中```包裹文本块的问题

原代码失效的核心原因:回车会把可编辑Div的内容拆分成多个文本节点,但原逻辑仅操作第一个文本节点;同时通过innerText索引定位的方式,无法和DOM节点的偏移量准确对应,导致换行后功能完全失效。

以下是简化后的实现代码,能正确处理包含回车的文本块:

$('button').on('click', function() {
    const editor = $('#cstory')[0];
    const selection = window.getSelection();
    if (selection.rangeCount === 0) return;

    let currentNode = selection.getRangeAt(0).startContainer;
    // 确保当前操作的是文本节点
    if (currentNode.nodeType !== Node.TEXT_NODE) {
        currentNode = currentNode.firstChild;
        if (!currentNode) return;
    }

    let startRange = null;
    let endRange = null;

    // 向前遍历节点,找到起始的```标记
    function findStartMarker(node) {
        if (!node) return false;
        const text = node.textContent;
        const markerIndex = text.lastIndexOf('```');
        if (markerIndex !== -1) {
            // 校验是否是独立的块起始标记(后接换行或位于文本开头)
            const afterMarker = text.slice(markerIndex + 3);
            if (afterMarker.startsWith('\n') || markerIndex === 0) {
                startRange = document.createRange();
                startRange.setStart(node, markerIndex);
                startRange.setEnd(node, markerIndex + 3);
                return true;
            }
        }
        // 遍历前一个兄弟节点,若没有则遍历父节点的前一个兄弟
        if (node.previousSibling) return findStartMarker(node.previousSibling);
        if (node.parentNode !== editor) return findStartMarker(node.parentNode.previousSibling);
        return false;
    }

    // 向后遍历节点,找到结束的```标记
    function findEndMarker(node) {
        if (!node) return false;
        const text = node.textContent;
        const markerIndex = text.indexOf('```');
        if (markerIndex !== -1) {
            // 校验是否是独立的块结束标记(前接换行或位于文本末尾)
            const beforeMarker = text.slice(0, markerIndex);
            if (beforeMarker.endsWith('\n') || markerIndex === text.length - 3) {
                endRange = document.createRange();
                endRange.setStart(node, markerIndex);
                endRange.setEnd(node, markerIndex + 3);
                return true;
            }
        }
        // 遍历后一个兄弟节点,若没有则遍历父节点的后一个兄弟
        if (node.nextSibling) return findEndMarker(node.nextSibling);
        if (node.parentNode !== editor) return findEndMarker(node.parentNode.nextSibling);
        return false;
    }

    // 找到成对标记后,选中整个块
    if (findStartMarker(currentNode) && findEndMarker(currentNode)) {
        const fullRange = document.createRange();
        fullRange.setStart(startRange.startContainer, startRange.startOffset);
        fullRange.setEnd(endRange.endContainer, endRange.endOffset);
        selection.removeAllRanges();
        selection.addRange(fullRange);
    }
});
.cstory{white-space:pre-wrap;min-height:100px;border:1px solid #ccc;padding:8px;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='cstory' id='cstory' contenteditable>
lorem sea

lorem ipsum
dolor sit
sky

lorem sky

lorem ipsum
dolor sit
sky

dolor sit
</div>
<br>
<button>CLICK</button>

关键逻辑说明

  1. 节点遍历:从光标所在的文本节点出发,向前/向后遍历所有关联的兄弟节点、父节点的兄弟节点,确保不会漏掉换行拆分后的任意节点。
  2. 标记校验:只认独立的块标记(起始标记后接换行、结束标记前接换行),避免误选中文本中零散出现的```字符。
  3. Range精准选中:通过匹配到的起始、结束标记位置,创建完整的Range对象,实现整个代码块的选中。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 11:52:42