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

如何让命令行式打字动画中指定字母(XYZ)显示为霓虹粉?

解决打字动画中高亮指定字符导致的循环异常问题

问题根源在于:直接用HTML标签修改文本后,原代码通过substring截取HTML字符串的方式会把标签的字符(比如<span class="neon-pink">)算入长度,导致实际显示的字符数和计数不匹配,进而触发错误的循环终止条件,让动画出现异常。

解决方案步骤

  1. 预处理文本,拆分字符单元:把需要高亮的字符单独包裹成HTML标签,并将整个文本拆分为独立的“显示单元”数组,每个单元要么是普通字符,要么是带高亮标签的字符。
  2. 修改打字逻辑,按单元拼接:不再通过截取HTML字符串的方式生成显示内容,而是逐个拼接预处理好的单元,确保计数和实际显示的字符完全一致。

修改后的完整代码

HTML

<p id="line1" class="hidden">ABCXYZDEF</p>
<p id="cursor-line" class="visible">&gt;<span class="typed-cursor">_</span></p>

CSS(保持原有样式不变)

body {
  font-family: monospace;
  background-color: black;
  color: white;
  text-align: center;
  margin-top: 21%;
}

.neon-pink {
  color: #ff00ff;
  /* Neon Pink color code */
}

.hidden {
  display: none;
  visibility: hidden;
}

/* ----- blinking cursor animation ----- */
.typed-cursor {
  opacity: 1;
  -webkit-animation: blink 0.95s infinite;
  -moz-animation: blink 0.95s infinite;
  -ms-animation: blink 0.95s infinite;
  -o-animation: blink 0.95s infinite;
  animation: blink 0.95s infinite;
}

@keyframes blink {
  0% { opacity: 1; }
  50% { opacity: 0; }
  100% { opacity: 1; }
}

@-webkit-keyframes blink {
  0% { opacity: 1; }
  50% { opacity: 0; }
  100% { opacity: 1; }
}

@-moz-keyframes blink {
  0% { opacity: 1; }
  50% { opacity: 0; }
  100% { opacity: 1; }
}

@-ms-keyframes blink {
  0% { opacity: 1; }
  50% { opacity: 0; }
  100% { opacity: 1; }
}

@-o-keyframes blink {
  0% { opacity: 1; }
  50% { opacity: 0; }
  100% { opacity: 1; }
}

JavaScript(核心修改部分)

// set typing speed and wait times
var timeInit = 400; // initial wait before typing first line
var timeGap = 1000; // wait time between each line
var timeChar = 110; // time until next letter

var cursorChar = '_';

var originId = ['line1'];
var originTextUnits = new Array();

// 预处理文本,拆分字符单元,高亮XYZ字符
function processText(rawText) {
  return rawText.split('').map(char => {
    if ('XYZ'.includes(char)) {
      return `<span class="neon-pink">${char}</span>`;
    }
    return char;
  });
}

for (var i = 0; i < originId.length; i++) {
  var rawText = document.getElementById(originId[i]).textContent;
  originTextUnits.push(processText(rawText));
}

var cursorLine = document.getElementById('cursor-line');

var currentTimeout;
var showCursor;

var typeWriter = function(index) {
  var loc = document.getElementById(originId[index]);
  var textUnits = originTextUnits[index];
  var unitCount = 0;

  // 逐个拼接字符单元实现打字动画
  var typeUnit = function() {
    currentTimeout = setTimeout(function() {
      loc.className = 'visible';
      unitCount += 1;
      // 拼接已处理的单元生成显示内容
      var showText = textUnits.slice(0, unitCount).join('');

      // 所有单元处理完成时终止循环
      if (unitCount === textUnits.length) {
        loc.innerHTML = '&gt;' + showText + '<span class="typed-cursor">' + cursorChar + '</span>';
      } else {
        loc.innerHTML = '&gt;' + showText + '<span class="typed-cursor">' + cursorChar + '</span>';
        typeUnit();
      }
    }, timeChar);
  };

  typeUnit();
};

// calculated time delays
var delayTime = [timeInit];
var cumulativeDelayTime = [timeInit];
for (var i = 0; i < originId.length; i++) {
  // 用单元数组长度计算时长,确保和实际显示字符数匹配
  var elapsedTimeLine = originTextUnits[i].length * timeChar + timeGap + timeChar * 2;
  delayTime.push(elapsedTimeLine);
  var sum = 0;
  for (var j = 0; j < delayTime.length; j++) {
    sum += delayTime[j];
  }
  cumulativeDelayTime.push(sum);
}

// calls setTimeout for each line
var typeLineTimeout = new Array();
for (var i = 0; i < originId.length; i++) {
  typeLineTimeout[i] = setTimeout(
    (function(index) {
      return function() {
        cursorLine.className = 'hidden';
        typeWriter(index);
      };
    })(i),
    cumulativeDelayTime[i]
  );
}

// stops all timeouts
var skip = function() {
  clearTimeout(currentTimeout);
  clearTimeout(showCursor);
  for (var i = 0; i < typeLineTimeout.length; i++) {
    clearTimeout(typeLineTimeout[i]);
  }
};

// 修复rewriteText函数,正确渲染高亮后的完整文本
var rewriteText = function(index) {
  var loc = document.getElementById(originId[index]);
  loc.innerHTML = '&gt; ' + originTextUnits[index].join('');
  loc.className = 'visible';
};

// trigger skip and rewrite on pressing enter or spacebar
window.onkeydown = function(key) {
  if (key.which === 13 || key.which === 32) {
    skip();
    originId.forEach(rewriteText);
    document.getElementById('cursor-line').className = 'visible';
  }
};

关键修改说明

  • 新增processText函数,将原始文本拆分为字符单元,对XYZ单独包裹高亮标签,确保每个可见字符对应一个独立单元。
  • 用originTextUnits存储预处理后的单元数组,替代原有的originText,避免HTML标签干扰长度计算。
  • 打字逻辑改为遍历单元数组逐个拼接,彻底解决标签字符导致的计数错误。
  • 时间计算部分改用单元数组的长度,确保动画时长和实际字符数匹配。
  • 修复rewriteText函数,正确渲染包含高亮标签的完整文本。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 16:24:57