打字機效果的實現與應用
前言
在 web 應用中,模擬編輯器或者模擬輸入框中文字啪啦啪啦輸入的效果,往往能夠吸引人們的眼球,讓用戶的注意力聚焦在輸入的內容上,其實使用的是 web 動畫模擬打字機效果,本文將和大家探討打字機效果的實現方式以及應用。
純 css 實現
最簡單的方式是莫過於直接使用 CSS 。大概思路是藉助 CSS3 的 @keyframe
動畫來不斷改變包含文字的容器的寬度,超出容器部分的文字隱藏不展示。
css 打字機效果
<style>
.typing {
font-size: 20px;
/* 初始寬度爲0 */
width: 0;
height: 30px;
border-right: 1px solid darkgray;
animation: write 4s steps(14) forwards,
blink 0.5s steps(1) infinite;
overflow: hidden;
}
@keyframes write {
0% {
width: 0;
}
100% {
width: 240px;
}
}
@keyframes blink {
50% {
/* transparent是全透明黑色(black)的速記法,即一個類似rgba(0,0,0,0)這樣的值。 */
border-color: transparent; /* #00000000 */
}
}
</style>
<body>
<div>
自在,輕盈,我本不想停留
</div>
</body>
Steps(<number_of_steps>,<direction>)
animation steps 可以讓動畫斷斷續續,而非連續執行。接收兩個參數:
第一個參數指定動畫分割的段數;
第二個參數可選,接受 start 和 end 兩個值,指定在每個間隔的起點或是終點發生階躍變化,默認爲 end。
可以看到其實現原理很簡單,打字效果其實就是改變容器的寬度實現的。 初始文字是全部在頁面上的,只是容器的寬度爲 0,設置文字超出部分隱藏,然後不斷改變容器的寬度; 設置 border-right
,並在關鍵幀上改變 border-color
爲 transparent
,右邊框就像閃爍的光標了。
優點是簡單,缺點也是有的,首先我們要先獲得文本的寬度,上面的截圖就是因爲寬度寫錯了,導致光標在文字後面,然後只支持 1 行。若想要支持多行,就得使用 JavaScript 了。
js 實現
setInterval 實現
<style>
/* 產生光標閃爍的效果 */
#content::after{
content: '|';
color:#000;
animation: blink 1s infinite;
}
@keyframes blink{
from{
opacity: 0;
}
to{
opacity: 1;
}
}
</style>
<div id='content'></div>
<script>
(function () {
// 獲取容器
const container = document.getElementById('content')
// 把需要展示的全部文字進行切割
const data = '自在,輕盈,我本不想停留'.split('')
// 需要追加到容器中的文字下標
let index = 0
let timer = null
function writing() {
if (index < data.length) {
// 追加文字
container.innerHTML += data[index ++]
// 也可以使用,clearTimeout取消setInterval的執行
// index === 4 && clearTimeout(timer)
} else {
clearInterval(timer)
}
console.log(timer) // 這裏會打印出 1 1 1 1 1 ...
}
// 使用 setInterval 時,結束後不要忘記進行 clearInterval
timer = setInterval(writing, 200)
})();
</script>
setInterval 版本的實現也很簡單,只需把要展示的文本進行切割,使用定時器不斷向 DOM 元素裏追加文字即可,同時使用::after
僞元素在 DOM 元素後面產生光標閃爍的效果。代碼和效果圖如下:
setTimeout 實現
和 setInterval 一樣,setTimeout 也可以實現
<style>
/* 產生光標閃爍的效果 */
#content::after{
content: '|';
color:#000;
animation: blink 1s infinite;
}
@keyframes blink{
from{
opacity: 0;
}
to{
opacity: 1;
}
}
</style>
<div id='content'></div>
<script>
(function () {
// 獲取容器
const container = document.getElementById('content')
// 把需要展示的全部文字進行切割
const data = '自在,輕盈,我本不想停留'.split('')
// 需要追加到容器中的文字下標
let index = 0
function writing() {
if (index < data.length) {
// 追加文字
container.innerHTML += data[index ++]
let timer = setTimeout(writing, 200)
}
}
writing()
})();
</script>
需要強調一點:定時器指定的時間間隔,表示的是何時將定時器的代碼添加到消息隊列,而不是何時執行代碼,所以真正何時執行代碼的時間是不能保證的,取決於何時被主線程的事件循環取到,並執行。
那如果想要實現暫停和播放,那就必須使用 clearTimeout()
方法來終止,
<div id='content'></div>
<button id='pause'>暫停</button>
<script>
// 獲取容器
const container = document.getElementById('content')
// 把需要展示的全部文字進行切割
const data = '最簡單的打字機效果實現'.split('')
// 需要追加到容器中的文字下標
let index = 0
let timer
document.querySelector('#pause').addEventListener('click',()=>{
clearTimeout(timer)
})
function writing() {
if (index < data.length) {
// 追加文字
container.innerHTML += data[index ++]
timer = setTimeout(writing, 200)
}
}
writing()
</script>
但除了暫停,還有回退,修改等操作,需要修改光標位置等,我們可以使用一個 npm 庫來搞定。
Typeit 實現
Typeit 官網效果
首先需要引如 cdn script
<script src="https://unpkg.com/typeit@8.6.0/dist/index.umd.js"></script>
或是使用 npm 安裝這個包
npm install typeit
官網首頁 demo 代碼
new TypeIt("#hero", {
speed: 50,
startDelay: 900,
})
.type("the mot versti", { delay: 100 })
.move(-8, { delay: 100 })
.type("s", { delay: 400 })
.move(null, { to: "START", instant: true, delay: 300 })
.move(1, { delay: 200 })
.delete(1)
.type("T", { delay: 225 })
.pause(200)
.move(2, { instant: true })
.pause(200)
.move(5, { instant: true })
.move(5, { delay: 200 })
.type("a", { delay: 350 })
.move(null, { to: "END" })
.type("le typing utlity")
.move(-4, { delay: 150 })
.type("i")
.move(null, { to: "END" })
.type(' on the <span>internet</span>', { delay: 400 })
.delete(".place", { delay: 800, instant: true })
.type('<em><strong>planet.</strong></em>', {
speed: 100,
})
.go();
代碼一目瞭然,支持暫停、刪除,移動、而且還支持 html。
需要注意的是 TypeIt 在商用項目上是收費的, 在個人或者開源項目上是免費的。商用項目需要支付 $19, 那麼有沒有免費的呢?
typed.js 實現
那如果想在商用項目上免費使用,可以使用 typed.js ,採用 MIT 開源協議,與 TypeIt 類似的 api
<script>
var typed = new Typed('#typed', {
stringsElement: '#typed-strings'
});
</script>
<div>
<p>Typed.js is a <strong>JavaScript</strong> library.</p>
<p>It <em>types</em> out sentences.</p>
</div>
<span></span>
對 seo 非常友好,它是在從頁面上的 HTML 元素讀取,再通過 js 動態插入。
打字機效果應用
程序講究的輸入和輸出,雖然我們在頁面上實現了動態輸入的效果,若能夠同步實現輸出,豈不是實現了編譯器的效果?
Sildev 使用 markdown 寫 PPT
之前分享的 Sildev[1],就完美地將輸入和輸出效果展現在頁面上
Sildev 輸入和輸出
源碼在這裏 [2]
new TypeIt(block.value, {
speed: 50,
startDelay: 900,
afterStep: () => {
code.value = JSON.parse(JSON.stringify(block.value!.innerText.replace('|', '')))
},
})
.type('<br><span># 歡迎使用 Slidev!</span><br><br>', { delay: 400 })
.type('爲開發者打造的演示文稿工具', { delay: 400 })
其主要原理是通過 afterStep
回調函數 將頁面上的輸入值,設置到 state 中,然後再使用 vue 中的 watch,監聽輸入值的變化,將 markdown 解析成 HTML 插入到頁面中。
import { ref, onMounted, watch } from 'vue'
import { parse } from '@slidev/parser'
...
watch([code, paused], () => {
if (paused.value)
return
try {
info.value = parse(code.value)
}
catch (e) {
}
})
...
實現方式簡單,但卻讓用戶一目瞭然,讓用戶不用看文檔就可以學會使用 markdown 寫 PPT。
動態簡歷
之前在知乎上看到 @方應杭用 vue 寫了一個會動的簡歷 [3],也是運用了打字機效果,將輸入和輸出完美的展現在瀏覽器裏,若不瞭解其原理會覺得很高大上,但實現代碼卻很簡單,源碼在這裏 [4]
會動的簡歷
學以致用
我之前使用 MDX 寫了一個微信排版編輯器 MDX Editor[5],正好少了一個首頁,能否加上打字機效果呢?
mdx-editor
可自定義組件、樣式、生成二維碼、代碼 diff 高亮,一鍵拷貝到微信,可導出 markdown 和 PDF。 關於代碼和原理就就不貼了,大致和 Sildev 差不多,只不過我使用的是 react 來實現,代碼已經開源 [6],若對你有幫助, 可以點個 star,感謝您的支持!
以上就是本文全部內容,希望這篇文章對大家有所幫助,也可以參考我往期的文章或者在評論區交流你的想法和心得,歡迎一起探索前端。
[1]Sildev: https://cn.sli.dev/
[2]Sildev demo 源碼: https://github.com/slidevjs/docs-cn/blob/main/.vitepress/theme/components/demo/Demo.vue
[3] 會動的簡歷: https://zhuanlan.zhihu.com/p/25541520
[4] 會動的簡歷源碼: https://github.com/jirengu-inc/animating-resume
[5]mdx-editor: https://editor.runjs.cool/
[6]mdx-editor 源碼: https://github.com/maqi1520/mdx-editor
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/BjMiSV9jkCO-IvEHJ76NBA