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

如何用JavaScript识别滚动textarea中当前显示的文本行?

解决方案:textarea滚动与右侧HTML展示区同步

一、精准识别textarea可见文本行

核心利用浏览器的caretPositionFromPoint() API,它能直接定位视觉可见区域的文本位置,自动处理textarea的自动换行问题:

1. 获取可见区域坐标与文本位置

const textarea = document.getElementById('markdown-textarea');

textarea.addEventListener('scroll', () => {
  const rect = textarea.getBoundingClientRect();
  // 获取可见区域顶部和底部的屏幕坐标
  const topPoint = textarea.caretPositionFromPoint(rect.left + 10, rect.top + 10);
  const bottomPoint = textarea.caretPositionFromPoint(rect.left + 10, rect.bottom - 10);

  if (!topPoint || !bottomPoint) return;

  // 转换为文本索引
  const startIndex = topPoint.offset;
  const endIndex = bottomPoint.offset;

2. 映射为文本行号

将textarea内容按换行符分割,通过索引匹配到对应的行:

const lines = textarea.value.split('\n');
  let currentOffset = 0;
  let startLine = 0;
  let endLine = lines.length - 1;

  // 匹配起始行
  for (let i = 0; i < lines.length; i++) {
    currentOffset += lines[i].length + 1; // +1 包含换行符长度
    if (currentOffset > startIndex) {
      startLine = i;
      break;
    }
  }

  // 匹配结束行
  currentOffset = 0;
  for (let i = 0; i < lines.length; i++) {
    currentOffset += lines[i].length + 1;
    if (currentOffset >= endIndex) {
      endLine = i;
      break;
    }
  }

  // 此时startLine/endLine就是当前可见的首尾行号
  syncPreview(startLine);
});

二、同步右侧HTML展示区滚动

需要提前建立markdown行与HTML元素的映射关系(渲染HTML时记录):

1. 构建行-元素映射表

假设你的markdown解析器会将连续行转换为HTML块(如段落、标题),渲染时记录每个块对应的markdown行范围:

// 示例:解析后生成的映射表,根据实际解析逻辑调整
const blockMap = [
  { startLine: 0, endLine: 2, element: document.getElementById('preview-h1') },
  { startLine: 3, endLine: 7, element: document.getElementById('preview-p1') },
  { startLine: 8, endLine: 12, element: document.getElementById('preview-ul1') },
  // ... 所有HTML块的映射
];

2. 滚动到对应HTML位置

function syncPreview(targetLine) {
  const previewContainer = document.getElementById('html-preview');
  // 找到包含目标行的HTML块
  const targetBlock = blockMap.find(block => targetLine >= block.startLine && targetLine <= block.endLine);
  
  if (targetBlock) {
    // 滚动到块的顶部,适配容器偏移
    previewContainer.scrollTop = targetBlock.element.offsetTop - previewContainer.offsetTop;
  }
}

三、性能与边界优化

  • 防抖处理:避免滚动事件频繁触发逻辑,使用requestAnimationFrame节流:
let isSyncing = false;
textarea.addEventListener('scroll', () => {
  if (!isSyncing) {
    window.requestAnimationFrame(() => {
      // 执行上述行识别与同步逻辑
      isSyncing = false;
    });
    isSyncing = true;
  }
});
  • 边界适配:当滚动到textarea顶部/底部时,直接将预览区滚动到对应端点:
if (textarea.scrollTop === 0) {
  previewContainer.scrollTop = 0;
  return;
}
if (textarea.scrollTop + textarea.clientHeight >= textarea.scrollHeight) {
  previewContainer.scrollTop = previewContainer.scrollHeight;
  return;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 22:53:01