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

如何实现PicoBlaze模拟器代码实时高亮且光标不偏移?兼容Firefox52

问题分析与解决方案

问题根源

  1. 光标位置获取错误:你尝试用edit.selectionStart是误区——selectionStart/selectionEnd仅适用于<input>或<textarea>,对contenteditable的<div>完全不生效,导致无法正确记录光标位置。
  2. 光标恢复逻辑错误:range.setStart(assemblyCodeDiv, start)的第二个参数是子节点索引,不是文本偏移量,根本定位不到正确位置;且替换innerHTML后原DOM节点被销毁,旧Range对象直接失效。
  3. 递归阻塞未重置:areWeHighlighting变量未在函数末尾重置,第一次高亮后,后续input事件会被直接拦截,无法触发实时高亮。

修复方案

1. 编写光标位置处理辅助函数

针对contenteditable的<div>,需要通过Range API计算光标相对于纯文本的偏移量,再遍历高亮后的DOM结构恢复位置:

// 遍历DOM节点,根据纯文本偏移量定位光标
function setCursorPosition(el, targetOffset) {
  const range = document.createRange();
  const selection = window.getSelection();
  let currentOffset = 0;
  let found = false;

  function traverse(node) {
    if (found) return;
    if (node.nodeType === Node.TEXT_NODE) {
      if (currentOffset + node.length >= targetOffset) {
        const actualOffset = Math.min(targetOffset - currentOffset, node.length);
        range.setStart(node, actualOffset);
        range.setEnd(node, actualOffset);
        found = true;
      } else {
        currentOffset += node.length;
      }
    } else {
      for (let i = 0; i < node.childNodes.length; i++) {
        traverse(node.childNodes[i]);
      }
    }
  }

  traverse(el);
  selection.removeAllRanges();
  selection.addRange(range);
}

2. 修改syntaxHighlighter核心函数

更新高亮逻辑,加入光标保存与恢复步骤:

let areWeHighlighting = false; // 确保变量可全局访问

function syntaxHighlighter() {
  if (areWeHighlighting) return;
  areWeHighlighting = true;

  const assemblyCodeDiv = document.getElementById("assemblyCode");
  let cursorOffset = 0;

  // 保存光标位置:计算相对于纯文本的偏移量
  const selection = window.getSelection();
  if (selection.rangeCount > 0) {
    const range = selection.getRangeAt(0);
    const preRange = document.createRange();
    preRange.selectNodeContents(assemblyCodeDiv);
    preRange.setEnd(range.startContainer, range.startOffset);
    cursorOffset = preRange.toString().length;
  }

  // 原文本转义(保留你的原有逻辑)
  const assemblyCode = assemblyCodeDiv.innerText.replace(/&/g, "&amp;")
                           .replace(/</g, "&lt;")
                           .replace(/>/g, "&gt;");

  // 执行你的语法高亮逻辑,生成highlightedText
  // ...(此处保留你原有的高亮代码,比如匹配指令、寄存器等)

  // 更新DOM
  assemblyCodeDiv.innerHTML = highlightedText;

  // 恢复光标位置
  setCursorPosition(assemblyCodeDiv, cursorOffset);

  // 重置标记,允许下次触发
  areWeHighlighting = false;
}

3. 绑定实时触发事件

取消footerScript.js中的注释,绑定input事件:

document.getElementById("assemblyCode").oninput = syntaxHighlighter;

Firefox 52兼容性说明

  • Firefox 52完全支持document.createRange()和window.getSelection(),上述代码无需额外兼容处理。
  • 避免使用ES6+高级特性(如箭头函数、可选链等),基础let/const语法在Firefox 52中可正常使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 23:23:13