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

多行文本打字光标效果实现:解决光标消失与末尾字符未变白问题

多行文本打字光标效果实现:解决光标消失与末尾字符未变白问题

嘿,我看了你遇到的两个问题——光标消失和每行最后一个字符一直黑,咱们一步步来解决它们:

问题根源分析

  • 光标消失:你每次处理完一行就移除了光标,最后添加的光标定位计算有偏差;而且初始HTML里的行元素自带文本,你创建span后直接移除第一个子节点,导致DOM节点索引混乱,影响光标位置和显示。
  • 最后字符变黑:childNodes的索引逻辑出错,当currentChar走到文本长度时,你试图修改currentChar-1的字符颜色,但因为节点索引混乱,这个操作没作用到正确的字符上。

修复后的完整代码

HTML

<div class="top-container">
  <h1>
    <span class="text" id="line1"></span><br>
    <span class="text" id="line2"></span><br>
    <span class="text" id="line3"></span>
  </h1>
</div>

CSS

.top-container h1 {
  font-size: 5rem;
  font-weight: 950;
  line-height: 1.2;
  white-space: nowrap;
  background-color: black;
  position: relative;
}

.top-container h1 .text {
  display: inline-block;
  position: relative;
}

.cursor {
  display: inline-block;
  width: 0.15em;
  height: 1em;
  background-color: white;
  animation: blink-caret 0.75s step-end infinite;
  vertical-align: bottom;
}

@keyframes blink-caret {
  50% {
    background-color: transparent;
  }
}

.button-container {
  display: flex;
  justify-content: space-evenly;
  align-items: center;
  width: 100%;
  margin-top: 200px;
}

JavaScript

document.addEventListener("DOMContentLoaded", function() {
  const lines = [
    { element: document.getElementById("line1"), text: "Lorem ipsum dolor" },
    { element: document.getElementById("line2"), text: "sit" },
    { element: document.getElementById("line3"), text: "amet, consectetur adipiscing elit." }
  ];

  let currentLine = 0;
  let currentChar = 0;
  let currentCursor = null;

  function createCursor() {
    const cursor = document.createElement("span");
    cursor.className = "cursor";
    return cursor;
  }

  function type() {
    if (currentLine < lines.length) {
      const line = lines[currentLine];
      const text = line.text;
      
      // 先清空行元素,避免原有文本干扰
      line.element.innerHTML = "";
      
      // 预先创建所有黑色字符span
      for (let i = 0; i < text.length; i++) {
        const span = document.createElement("span");
        span.textContent = text[i];
        span.style.color = "black";
        line.element.appendChild(span);
      }

      // 创建光标并添加到当前行
      currentCursor = createCursor();
      line.element.appendChild(currentCursor);

      function typeChar() {
        if (currentChar < text.length) {
          // 直接通过children获取span,避免childNodes包含文本节点的问题
          line.element.children[currentChar].style.color = "white";
          currentChar++;
          setTimeout(typeChar, 40);
        } else {
          // 确保最后一个字符变白
          line.element.children[currentChar - 1].style.color = "white";
          // 移除当前行的光标
          if (currentCursor) {
            currentCursor.remove();
            currentCursor = null;
          }
          currentLine++;
          currentChar = 0;
          setTimeout(type, 200); // 增加换行延迟,体验更自然
        }
      }

      typeChar();
    } else {
      // 在最后一行添加闪烁光标
      const lastLine = lines[lines.length - 1].element;
      currentCursor = createCursor();
      lastLine.appendChild(currentCursor);
    }
  }

  type();
});

关键修改点

  1. HTML优化:清空了行元素的初始文本,避免后续DOM操作混乱。
  2. 光标逻辑调整:
    • 单独封装光标创建函数,统一管理光标实例
    • 去掉了容易出错的绝对定位,改用inline-block+垂直对齐,确保光标始终显示在正确位置
  3. 字符颜色修复:使用children而非childNodes获取字符span,因为children只返回元素节点,不会包含文本节点,索引更准确
  4. DOM清理:每行开始前先清空元素内容,避免旧节点干扰

这样修改后,光标会正常闪烁,每行的所有字符都会正确变白,完全解决你遇到的两个问题~

备注:内容来源于stack exchange,提问作者Andy G

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 11:34:31