前端实现人工智能常见的打字机效果

2,586 阅读6分钟

打字机效果是一种很酷的动画,它使文本看起来就像在页面上键入一样。

有很多方法可以使用打字机效果来增强网站的用户体验。例如,可以使用它来介绍主页上的关键概念或功能,或在整个网站中强调重要文本。

在这篇文章中,我们将探讨使用纯 CSS 和基于 JavaScript 的解决方案创建打字机效果的不同方法。出于演示目的,我们将使用以下引用。

  • Learning never exhausts the mind — Leonardo da Vinci
  • You teach best what you most need to learn — Richard Bach
  • In youth we learn; in age we understand — Marie von Ebner-Eschenbach

标记

若要开始使用打字机效果,需要先创建结构 。此布局有两个基本元素:容器和内部元素。外部元素稍后将添加样式,将所有内容结合在一起。内部元素是显示文本的位置。

<div class="container">
  <div class="typewriter"></div>
</div>

使用 steps()函数

创建打字机效果有两种方法。第一种方法是纯 CSS 解决方案,它完全依赖于 CSS 动画,而不使用任何 JavaScript 代码。

为了创建打字机效果,我们修改 width 属性的关键 typing 帧将内部元素的宽度从 0% 增加到 100%。

@keyframes typing {
    from {
        width: 0%;
    }
    to {
        width: 100%;
    }
}

我们从 0% 的宽度开始,这意味着没有输入任何字符。在动画结束时,元素宽度设置为原始全宽,这意味着所有字符都已完全键入。

挑战在于指出,在动画持续时间时间轴的每一步中,单个字符以从左到右的顺序出现。幸运的是,CSS 为此提供了 step() 计时功能。我们将步数传递给函数,动画执行相应的步数。

在我们的示例中,总步数与总字符数相同。如果我们将效果用于 Learning never exhausts the mind ,则步数为 48。

console.log('Learning never exhausts the mind'.length); // 48

动画声明可能如下所示:

.typewritter {
    animation: typing 4s steps(48);
}

闪烁光标

为了使打字的效果更加逼真,我们希望在文本末尾添加一个闪烁的光标。有几种方法可以做到这一点,但在这种方法中,我们可以使用文本元素的右边框,而不是只为光标创建一个新元素。

首先,我们使文本的右边框透明。然后,我们在动画结束时将边框的颜色动画化为较深的阴影,以创建闪烁效果。

.typewritter {
    border-right: 4px solid transparent;
}

@keyframes blink {
    from {
        border-right-color: transparent;
    }

    to {
        border-right-color: rgb(15 23 42);
    }
}

现在是使用 CSS 将动画与文本组合在一起的最佳时机。只需用逗号分隔动画即可。

例如,在下面的代码中,文本元素同时运行两个动画。第一个动画创建持续 4 秒的打字效果。第二个动画创建一个闪烁的光标,该光标反复淡入和淡出。

.typewritter {
    animation: typing 4s steps(48), blink 1s infinite;
}

让我们回顾一下到目前为止我们所采取的步骤的进展情况。

若要使光标更可自定义,需要为其创建一个新元素。我们将它称为 cursor 元素并将其添加到容器中。

<div class="container">
    <div class="typewritter">Learning never exhausts the mind</div>
    <div class="cursor">|</div>
</div>

由于文本和光标元素是水平对齐的,因此我们将对容器使用 CSS flexbox。

.container {
    display: flex;
    align-items: center;
}

要创建闪烁效果,可以随时间更改光标的背景颜色。动画在光标元素上运行,而不是像上一节那样在文本元素上运行。请记住,光标具有透明的文本颜色,因此字符是不可见的  | 。

.cursor {
    background-color: rgb(15 23 42);
    color: transparent;
    width: 4px;
    animation: blink 1s infinite; 
}

@keyframes blink { 
    0%, 100% {
        background-color: transparent;
    }

    50% {
        background-color: rgb(15 23 42);
    }
}

查看这些动画的实际效果:

虽然该 steps() 函数可以创建流畅的动画,但它确实有一个缺点——我们需要事先知道总步骤数。这意味着,如果我们想对不同的文本进行动画处理,我们必须更新 CSS 代码,这使得代码的可重用性降低。

遗憾的是,这种方法不适用于动态文本。为了解决这个问题,让我们继续下一节。

动态更新文本

在本节中,我们将探讨使用 JavaScript 动态更新文本的方法。通过使用函数 setTimeout() 和一点代码,我们可以一次显示一个字符。

为了实现此效果,我们将定义一个名为的函数 type ,该函数每 100 毫秒调用一次。该函数检查是否已显示最后一个字符,如果没有,则显示下一个字符。

type 函数使用调用 charIndex 的变量来跟踪最后显示的字符的索引。然后,我们检查此索引是否小于文本的长度。如果是,我们使用该 charAt() 函数显示下一个字符并将索引增加 1。

const content = 'Learning never exhausts the mind';
const textEle = document.getElementById('text');

let charIndex = 0;
const type = () => {
    if (charIndex < content.length) {
        textEle.textContent += content.charAt(charIndex);
        charIndex++;
        setTimeout(type, 100);
    }
};

要开始效果,只需调用该 type 函数。

实际上,光标仅在我们停止打字时闪烁。但是我们可以通过将闪烁的动画移动到一个单独的类来改变这一点。

.cursor__blink {
    animation: blink 1s infinite;
}

此类将在光标元素中添加或删除,具体取决于文本是否已完全显示。

为了实现这一点,我们可以向 type()  函数添加一些逻辑。在下面的示例中,我们将使用  remove()  和  add()  函数动态管理 blinking 类。

const cursorEle = document.getElementById('cursor');
const type = () => {
    if (charIndex < content.length) {
        cursorEle.classList.remove('cursor__blink');
        // ...
    } else {
        cursorEle.classList.add('cursor__blink');
    }
};

现在,让我们深入了解这一切是如何工作的。

多个文本

让我们将示例提升到一个新的水平,并添加对多个文本的支持。为此,我们需要创建一个新函数来模拟 Backspace 键并擦除文本。

我们将这个函数 erase() 称为 。它将以与  type() 函数相反的方式工作。它将从文本元素中删除最后一个字符,并将索引减少 1,直到删除所有字符。该  cursor__blink  类将相应地在游标元素中添加或删除。

const erase = () => {
    if (charIndex > 0) {
        cursorEle.classList.remove('cursor__blink');
        textEle.textContent = textEle.textContent.slice(0, charIndex - 1);
        charIndex--;
        setTimeout(erase, 100);
    } else {
        cursorEle.classList.add('cursor__blink');
    }
};

为了跟踪我们正在处理的当前文本,我们需要调用一个新索引 arrayIndex 来访问文本列表。该  type() 函数将更新,以便我们使用当前文本。当当前文本完全显示时,我们将在 500 毫秒后开始擦除它。

const texts = [
    'Learning never exhausts the mind',
    'You teach best what you most need to learn',
    'In youth we learn; in age we understand',
];
let arrayIndex = 0;

const type = () => {
    if (charIndex < texts[arrayIndex].length) {
        cursorEle.classList.remove('cursor__blink');
        textEle.textContent += texts[arrayIndex].charAt(charIndex);
        charIndex++;
        setTimeout(type, 100);
    } else {
        cursorEle.classList.add('cursor__blink');
        setTimeout(erase, 500);
    }
};

同样,一旦当前文本被擦除干净,我们将等待 500 毫秒,然后再键入下一个文本。下面是函数 erase 如下所示的示例:

const erase = () => {
    if (charIndex > 0) {
        cursorEle.classList.remove('cursor__blink');
        textEle.textContent = textEle.textContent.slice(0, charIndex - 1);
        charIndex--;
        setTimeout(erase, 100);
    } else {
        cursorEle.classList.add('cursor__blink');
        arrayIndex++;
        if (arrayIndex > texts.length - 1) {
            arrayIndex = 0;
        }
        setTimeout(type, 500);
    }
};

现在,是时候看最后的演示了!

原文: phuoc.ng/collection/…