<style>
/* 文本容器样式 */
.text-container {
width: 600px;
position: relative;
font-size: 16px;
font-family: Arial, sans-serif;
line-height: 1.5;
word-wrap: break-word;
background-color: #f0f0f0;
}
/* 文本内容样式 */
.text {
position: absolute;
display: block;
}
/* 光标样式 */
.cursor {
float: left;
position: absolute;
width: 4px;
height: 16px;
background-color: #000;
animation: blink 1s infinite; /* 添加光标闪烁动画 */
}
@keyframes blink {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0;
}
}
</style>
<body>
<div class="text-container">
<div class="text"></div>
<div class="cursor"></div>
</div>
<script>
const textContainer = document.querySelector('.text-container')
const textElem = document.querySelector('.text')
const cursor = document.querySelector('.cursor')
async function autoAppend() {
function delay(num) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, num)
})
}
function transfer(text) {
return text
}
const content = `在软件管理的领域里存在着被称作“依赖地狱”的死亡之谷,系统规模越大,加入的包越多,你就越有可能在未来的某一天发现自己已深陷绝望之中。
在依赖高的系统中发布新版本包可能很快会成为噩梦。如果依赖关系过高,可能面临版本控制被锁死的风险(必须对每一个依赖包改版才能完成某次升级)。而如果依赖关系过于松散,又将无法避免版本的混乱(假设兼容于未来的多个版本已超出了合理数量)。当你项目的进展因为版本依赖被锁死或版本混乱变得不够简便和可靠,就意味着你正处于依赖地狱之中。
作为这个问题的解决方案之一,我提议用一组简单的规则及条件来约束版本号的配置和增长。这些规则是根据(但不局限于)已经被各种封闭、开放源码软件所广泛使用的惯例所设计。为了让这套理论运作,你必须先有定义好的公共 API。这可能包括文档或代码的强制要求。无论如何,这套 API 的清楚明了是十分重要的。一旦你定义了公共 API,你就可以透过修改相应的版本号来向大家说明你的修改。考虑使用这样的版本号格式:X.Y.Z(主版本号.次版本号.修订号)修复问题但不影响 API 时,递增修订号;API 保持向下兼容的新增及修改时,递增次版本号;进行不向下兼容的修改时,递增主版本号。`
let result = '';
for (let i = 0; i <= content.length; i++) {
let text = content.slice(0, i);
result = transfer(text);
textElem.innerHTML = result;
updateCursor(textElem);
await delay(100)
}
}
function getLastTextNode(node) {
if (node.nodeType === node.TEXT_NODE) {
return node;
}
const children = node.childNodes;
for (let i = children.length - 1; i >= 0; i--) {
const child = children[i];
const result = getLastTextNode(child);
if (result) {
return result;
}
return null;
}
}
function updateCursor(textElem) {
// 1.追加一个文字到末尾
const lastTextNode = getLastTextNode(textElem);
console.log(textElem.innerHTML);
const textNode = document.createTextNode(' ');
if (lastTextNode) {
lastTextNode.parentNode.appendChild(textNode);
} else {
textElem.appendChild(textNode);
}
// 2. 获取追加的文字的位置
const range = document.createRange();
range.setStart(textNode, 0);
range.setEnd(textNode, 0);
const rect = range.getBoundingClientRect();
// 3. 根据位置设置光标的位置
const containerRect = textContainer.getBoundingClientRect();
const x = rect.x - containerRect.x;
const y = rect.y - containerRect.y;
cursor.style.transform = `translate(${x}px,${y}px)`;
console.log(textNode);
// 4 .移除追加的文字
textNode.parentNode.removeChild(textNode);
}
autoAppend();
</script>
</body>