关于首页打字机效果

8/23/2021 Vue

如何实现首页打字机效果

# 一、 用到的技术

# 二、实现思路

基础实现思想 B 站有小教程我就不赘述了,主要讲讲怎么在博客中应用。

bilibili:【CSS】打字特效 (opens new window)

# 三、在博客系统中应用

你需要知道的是在 VuePress 中,所有在 .vuepress/components 中找到的 *.vue 文件将会自动地被注册为全局的异步组件,如:

.
└─ .vuepress
   └─ components
      ├─ demo-1.vue
      ├─ OtherComponent.vue
      └─ Foo
         └─ Bar.vue
1
2
3
4
5
6
7

你可以直接使用这些组件在任意的 Markdown 文件中(组件名是通过文件名提取到的):

<demo-1/>
<OtherComponent/>
<Foo-Bar/>
1
2
3

于是我们在 components 目录下新建一个 NewFont.vue 文件,并填入以下代码:

<template>
  <div></div>
</template>
1
2

接下来在你的首页文件 README.md 文件中应用即可。

// ...

<NewFont />
1
2
3

我的目录结构如下:

# 四、普通版本(.html)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      :root {
        font-size: 20px;
      }

      body {
        display: flex;
        justify-content: center;
        align-items: center;
        min-height: 100vh;
      }

      h1 {
        margin: 0;
        padding: 0;
        /* 必须是等宽字体 */
        font-family: monospace;
        /* 由于是等宽字体,1ch 等于 任何数字、英文、符号的宽度 */
        /* width: 1ch; */
        position: relative;
        /* overflow: hidden; */
        /* animation: 1s typing forwards steps(13); */
      }

      h1::after {
        content: "";
        display: inline;
        position: absolute;
        width: 5px;
        height: 2ch;
        background-color: #000;
        border-radius: 2px;
        right: -0.5ch;
      }

      h1.ended::after {
        animation: 1.1s cursor steps(2, jump-none) infinite;
      }

      h1 span {
        --delay: 10s;
        display: inline-block;
        overflow: hidden;
        width: 0ch;
        animation: 0.1s text-in ease-in-out forwards;
        /* animation: 0.1s text-out ease-in-out forwards; */
        animation-delay: var(--delay);
      }

      @keyframes text-in {
        from {
          width: 0ch;
        }

        to {
          width: 2ch;
        }
      }

      @keyframes text-out {
        from {
          width: 2ch;
        }

        to {
          width: 0ch;
        }
      }

      @keyframes cursor {
        from {
          opacity: 0;
        }

        to {
          opacity: 1;
        }
      }
    </style>
  </head>

  <body>
    <script>
      let strs = [
        {
          title: "没有梦想,和咸鱼有什么区别",
          stop: 5,
        },
        {
          title: "没有什么能够顾阻你,前进的步伐",
          stop: 10,
          // stop: [4, 13]
        },
      ];
      // 当前进行到第几行
      let currentIndex = 0;
      let h1 = null;
      let spans = null;

      setTimeout(() => {
        h1 = document.createElement("h1");
        document.body.appendChild(h1);

        init();
      }, 2000);

      function init() {
        if (currentIndex == strs.length) {
          currentIndex = 0;
        }
        h1.innerHTML = strs[currentIndex].title;
        h1.innerHTML = h1.textContent.replace(/\S/g, "<span>$&</span>");

        let delay = 0;
        spans = [...document.querySelectorAll("span")];
        spans.forEach((span, i) => {
          delay += 0.1;
          if (strs[currentIndex].stop instanceof Array) {
            if (strs[currentIndex].stop.includes(i)) {
              delay += 0.3;
            }
          } else {
            if (strs[currentIndex].stop == i) {
              delay += 0.3;
            }
          }

          span.style.setProperty("--delay", `${delay}s`);
        });

        h1.addEventListener("animationend", lastEnd);
      }

      function lastEnd(e) {
        if (e.target == document.querySelector("h1 span:last-child")) {
          h1.classList.add("ended");
          setTimeout(() => {
            h1.removeEventListener("animationend", lastEnd);
            let delay = 0;

            spans.reverse().forEach((span, i) => {
              h1.classList.remove("ended");
              span.style.width = "2ch";
              span.style.animation = "0.1s text-out ease-in-out forwards";
              delay += 0.05;
              // 回去停顿功能
              // if (strs[currentIndex].stop instanceof Array) {
              //   if (strs[currentIndex].stop.includes(spans.length - i)) {
              //     delay += 0.3
              //   }
              // } else {
              //   if (strs[currentIndex].stop == spans.length - i) {
              //     delay += 0.3
              //   }
              // }
              span.style.animationDelay = `${delay}s`;
            });
            h1.addEventListener("animationend", firstEnd);
          }, 2000);
        }
      }

      function firstEnd(e) {
        if (e.target == document.querySelector("h1 span:first-child")) {
          spans.forEach((item) => {
            item.remove();
          });
          h1.removeEventListener("animationend", firstEnd);
          currentIndex++;
          // h1.classList.add('ended')
          // h1.classList.remove('ended')
          init();
        }
      }
    </script>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184

# 五、效果

最后更新于: 2021年9月15日星期三晚上10点10分
Dawn
DDRKirby(ISQ)