实现打字机特效
該案例學(xué)習(xí)自B站UP主xiao-high
打印多條文段可以參考一下這里:傳送門。案例見(jiàn)博客個(gè)人簡(jiǎn)介的應(yīng)用,點(diǎn)這里看效果。(打印一段文字后,再打印一段,覆蓋前邊的內(nèi)容)
介紹
文本一個(gè)一個(gè)的顯示,同時(shí)有光標(biāo)閃爍效果。
點(diǎn)擊這里查看效果:傳送門
動(dòng)手制作
新建一個(gè)HTML文件。
<!DOCTYPE html> <html> <head><meta charset="utf-8" /><title>qsdbl</title> </head> <body></body> </html>body
添加一個(gè)div,class名為text,用于控制文本和光標(biāo)的大小。div內(nèi)部添加兩個(gè)span,分別作為文本和光標(biāo)的容器。光標(biāo)為符號(hào)|。
<div class="text"><span class="word"></span><span class="gbiao">|</span> </div>css
去除瀏覽器默認(rèn)的margin、padding值。
* {margin: 0;padding: 0; }body設(shè)置讓div居中顯示,設(shè)置一個(gè)徑向漸變背景。
body {height: 100vh;/*讓文本居中*/display: flex;align-items: center;justify-content: center;/*徑向漸變*/background: radial-gradient(#000000, rgb(31, 77, 20)); }設(shè)置div內(nèi)的字體顏色為白色,字體大小在后邊js代碼中設(shè)置。
.text {color: #fff;text-align:center; }實(shí)現(xiàn)光標(biāo)閃爍
制作光標(biāo)閃爍動(dòng)畫:動(dòng)畫設(shè)置兩幀,透明度從0到100。
@keyframes flash {from {opacity: 0;}to {opacity: 1;} }光標(biāo)應(yīng)用該動(dòng)畫,動(dòng)畫播放時(shí)間為0.5秒,線性播放,循環(huán)播放。同時(shí)設(shè)置左外邊距為5px。
.text .gbiao {margin-left: 5px;animation: flash 0.5s linear infinite;/*讓光標(biāo)閃爍*/ }script
參數(shù)說(shuō)明:
- fontSize,字體大小
- word,顯示文本的span標(biāo)簽
- str,文本
在進(jìn)行繪制之前,我們需要確定打開(kāi)HTML文件的設(shè)備是pc還是手機(jī)。從而指定不同的fontSize。
var ua = navigator.userAgent.toLowerCase(); if(/AppleWebKit.*Mobile/i.test(navigator.userAgent) || (/MIDP|SymbianOS|NOKIA|SAMSUNG|LG|NEC|TCL|Alcatel|BIRD|DBTEL|Dopod|PHILIPS|HAIER|LENOVO|MOT-|Nokia|SonyEricsson|SIE-|Amoi|Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|ZTE/.test(navigator.userAgent)) || ua.match(/MicroMessenger/i) == "micromessenger"){var fontSize = 50;//手機(jī)字體大小 }else{var fontSize = 28;//pc字體大小 }設(shè)置文本大小
//設(shè)置文本大小let textSize = document.querySelector('.text');textSize.style.fontSize = fontSize + "px";上邊的js代碼可以使用CSS中的@media 查詢來(lái)實(shí)現(xiàn),具體代碼如下:
在前邊css的.text中添加字體大小:(PC端)
font-size: 28px;在前邊的css后邊再添加一個(gè)style標(biāo)簽,指定移動(dòng)端的字體大小。代碼如下:
<style type="text/css"> @media(max-width: 500px) {.text{font-size: 50px;} } </style>判斷設(shè)備類型的js代碼和設(shè)置文本大小的js代碼就可以刪掉了。
添加要顯示的文本
let str = "你好,我是輕率的保羅!很高興見(jiàn)到你!"; //要顯示的文本通過(guò)class名選擇顯示文本的span標(biāo)簽
//獲取文本顯示的span let word = document.querySelector('.word');實(shí)現(xiàn)打字機(jī)效果
有了str和word我們就可以實(shí)現(xiàn)打字機(jī)效果了。將實(shí)現(xiàn)打字機(jī)效果封裝在一個(gè)方法內(nèi),方法名showText
//實(shí)現(xiàn)打字機(jī)效果 function showText() {}我們定義幾個(gè)變量:
- myflag,布爾值,用于后邊的正倒放中
- time,每個(gè)字符顯示的時(shí)間長(zhǎng)度
- timewait,正倒放等待時(shí)間
實(shí)現(xiàn)正放
我們規(guī)定,正放就是從沒(méi)有顯示字符到顯示出全部的文本的過(guò)程。反之為倒放。
正放思路:使用一個(gè)for循環(huán),循環(huán)次數(shù)為要顯示的文本的個(gè)數(shù),每進(jìn)入一個(gè)循環(huán)就截取要顯示的文本的一部分顯示在頁(yè)面上。例如第一次進(jìn)入for循環(huán),截取“你”;第二次進(jìn)入for循環(huán),截取“你好”;第三次進(jìn)入for循環(huán),截取“你好,”;第四次進(jìn)入for循環(huán),截取“你好,我”;。。。代碼實(shí)現(xiàn)如下:
for (let n = 1; n <= str.length; n++) { //正放word.innerHTML = str.substr(0, n); } //substr(start,length)方法可在字符串中抽取從 start 下標(biāo)開(kāi)始的指定數(shù)目的字符。可是電腦運(yùn)行速度都是很快的,一瞬間for循環(huán)就執(zhí)行完了,也就是說(shuō)我們看不到文本一個(gè)一個(gè)的顯示出來(lái)。我們需要控制每一次截取文本顯示到頁(yè)面的時(shí)間。
我們可以使用一個(gè)定時(shí)器,隔指定時(shí)間執(zhí)行定義在其內(nèi)部的函數(shù)。前邊我們定義了每個(gè)字符顯示的時(shí)間為time=300毫秒,前一個(gè)字符等待顯示的時(shí)間為0,前兩個(gè)字符等待顯示的時(shí)間為time,前三個(gè)字符等待顯示的時(shí)間為兩個(gè)time,前四個(gè)字符等待顯示的時(shí)間為三個(gè)time,。。。所以越往后時(shí)間越長(zhǎng)。代碼實(shí)現(xiàn)如下:
setTimeout(function (){word.innerHTML = str.substr(0, n); },(n - 1) * time);//單位是毫秒所以實(shí)現(xiàn)正放代碼應(yīng)該為:
for (let n = 1; n <= str.length; n++) { //正放setTimeout(function() { //定時(shí)器word.innerHTML = str.substr(0, n);}, (n - 1) * time); }實(shí)現(xiàn)倒放
倒放與正放剛剛好相反。正放是先顯示前一個(gè)字符,再顯示前兩個(gè)字符,。。。倒放是先顯示全部的字符,然后少顯示一個(gè),再然后少顯示兩個(gè),。。。所以j的初始值為字符的長(zhǎng)度str.length。時(shí)間變成了str.length - j ,j越來(lái)越小,str.length不變,所以越往后時(shí)間越長(zhǎng),跟前邊正放一樣。代碼實(shí)現(xiàn)如下:
for (let j = str.length; j >= 0; j--) { //倒放setTimeout(function() { //定時(shí)器word.innerHTML = str.substr(0, j);}, (str.length - j) * time); }正/倒放結(jié)合
實(shí)現(xiàn)的效果是先正放,然后倒放,再然后是正放一直循環(huán)下去。這里我們需要用到一個(gè)周期定時(shí)器,每隔一定的時(shí)間(正放或倒放結(jié)束后),就執(zhí)行一次倒放或正放。
setInterval(function (){},毫秒數(shù));每隔一定的時(shí)間,這個(gè)時(shí)間我們可以通過(guò)str.length * time來(lái)計(jì)算,str.length * time為一次正放或倒放所用的時(shí)間,如果想讓正放倒放相隔一定的時(shí)間,我可以再添加一個(gè)等待時(shí)間,即前邊定義的timewait。
setInterval(function (){}, str.length * time + timewait);要實(shí)現(xiàn)一次正放一次倒放交替執(zhí)行,我們需要用到在前邊定義的布爾類型變量myflag,配合if-else語(yǔ)句即可實(shí)現(xiàn)。代碼如下:
if(myflag){//正放 }else{//倒放 } myflag = !myflag;所以正/倒放結(jié)合完整代碼如下:
setInterval(function(myflag) {if (this.myflag) {for (let i = 1; i <= str.length; i++) { //正放setTimeout(function() { //定時(shí)器word.innerHTML = str.substr(0, i);}, (i - 1) * time);}} else {for (let j = str.length; j >= 0; j--) { //倒放setTimeout(function() { //定時(shí)器word.innerHTML = str.substr(0, j);}, (str.length - j) * time);}}this.myflag = !this.myflag; }, str.length * time + timewait);到這里,實(shí)現(xiàn)打字機(jī)效果的函數(shù)showText,貌似就已經(jīng)完成了。不過(guò)我在實(shí)際的測(cè)試中發(fā)現(xiàn)有一個(gè)bug,與傳遞到周期定時(shí)器內(nèi)的參數(shù)myflag有關(guān)。導(dǎo)致第一次正放沒(méi)有顯示,到了倒放才開(kāi)始顯示文本。這個(gè)bug目前我修復(fù)不了,不過(guò)我在周期定時(shí)器的前邊添加了一個(gè)正放,可以掩蓋掉那個(gè)bug。如果你解決了這個(gè)bug請(qǐng)一定要跟我分享一下解決方法。函數(shù)showText未掩蓋bug的完整代碼如下:
//實(shí)現(xiàn)打字機(jī)效果 function showText() {let myflag = true;let time = 300; //每個(gè)字符顯示的時(shí)間let timewait = 2000; //正倒放等待時(shí)間setInterval(function(myflag) {if (this.myflag) {for (let i = 1; i <= str.length; i++) { //正放setTimeout(function() { //定時(shí)器word.innerHTML = str.substr(0, i);}, (i - 1) * time);}} else {for (let j = str.length; j >= 0; j--) { //倒放setTimeout(function() { //定時(shí)器word.innerHTML = str.substr(0, j);}, (str.length - j) * time);}}this.myflag = !this.myflag;}, str.length * time + timewait); }函數(shù)showText掩蓋bug后的完整代碼如下:
//實(shí)現(xiàn)打字機(jī)效果 function showText() {let myflag = true;let time = 300; //每個(gè)字符顯示的時(shí)間let timewait = 2000; //正倒放等待時(shí)間for (let n = 1; n <= str.length; n++) { //正放setTimeout(function() { //定時(shí)器word.innerHTML = str.substr(0, n);}, (n - 1) * time);}setInterval(function(myflag) {if (this.myflag) {for (let i = 1; i <= str.length; i++) { //正放setTimeout(function() { //定時(shí)器word.innerHTML = str.substr(0, i);}, (i - 1) * time);}} else {for (let j = str.length; j >= 0; j--) { //倒放setTimeout(function() { //定時(shí)器word.innerHTML = str.substr(0, j);}, (str.length - j) * time);}}this.myflag = !this.myflag;}, str.length * time + timewait); }最后,我們需要調(diào)用一下這個(gè)函數(shù),才能使打字機(jī)效果生效。我這里是添加了一個(gè)定時(shí)器,頁(yè)面加載完成之后過(guò)1s再調(diào)用實(shí)現(xiàn)打字機(jī)效果的函數(shù)。代碼如下:
//打開(kāi)頁(yè)面1s后顯示文本 setTimeout(showText, 1000);源碼
至此全部的代碼都完成了。下邊是全部代碼整合:
<!DOCTYPE html> <html><head><meta charset="utf-8" /><title>qsdbl</title></head><body><div class="text"><span class="word"></span><span class="gbiao">|</span></div></body><style>* {margin: 0;padding: 0;}body {height: 100vh;/*讓文本居中*/display: flex;align-items: center;justify-content: center;/*徑向漸變*/background: radial-gradient(#000000, rgb(31, 77, 20));}.text {color: #fff;}.text .gbiao {margin-left: 5px;animation: flash 0.5s linear infinite;/*讓光標(biāo)閃爍*/font-weight: bold;}@keyframes flash {from {opacity: 0;}to {opacity: 1;}}</style><script>var ua = navigator.userAgent.toLowerCase();if (/AppleWebKit.*Mobile/i.test(navigator.userAgent) || (/MIDP|SymbianOS|NOKIA|SAMSUNG|LG|NEC|TCL|Alcatel|BIRD|DBTEL|Dopod|PHILIPS|HAIER|LENOVO|MOT-|Nokia|SonyEricsson|SIE-|Amoi|Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|ZTE/.test(navigator.userAgent)) || ua.match(/MicroMessenger/i) == "micromessenger") {var fontSize = 50; //手機(jī)字體大小} else {var fontSize = 28; //pc字體大小}//設(shè)置文本大小let textSize = document.querySelector('.text');textSize.style.fontSize = fontSize + "px";let str = "你好,我是輕率的保羅!很高興見(jiàn)到你!"; //要顯示的文本//獲取文本顯示的spanlet word = document.querySelector('.word');//打開(kāi)頁(yè)面1s后顯示文本setTimeout(showText, 1000);//實(shí)現(xiàn)打字機(jī)效果function showText() {let myflag = true;let time = 300; //每個(gè)字符顯示的時(shí)間let timewait = 2000; //正倒放等待時(shí)間for (let n = 1; n <= str.length; n++) { //正放setTimeout(function() { //定時(shí)器word.innerHTML = str.substr(0, n);}, (n - 1) * time);}setInterval(function(myflag) {if (this.myflag) {for (let i = 1; i <= str.length; i++) { //正放setTimeout(function() { //定時(shí)器word.innerHTML = str.substr(0, i);}, (i - 1) * time);}} else {for (let j = str.length; j >= 0; j--) { //倒放setTimeout(function() { //定時(shí)器word.innerHTML = str.substr(0, j);}, (str.length - j) * time);}}this.myflag = !this.myflag;}, str.length * time + timewait);}</script> </html>修復(fù)bug
使用閉包來(lái)解決bug,詳細(xì)筆記訪問(wèn)這里。(這里的也是使用了閉包,不過(guò)定時(shí)器內(nèi)并沒(méi)有使用到外邊定義的標(biāo)志位myflag,函數(shù)定義的問(wèn)題。定時(shí)器內(nèi)的this.myflag不是外邊定義的myflag,而是匿名函數(shù)傳遞進(jìn)來(lái)的空值重新被后邊的this.myflag = !this.myflag;語(yǔ)句賦值了的定時(shí)器內(nèi)的局部變量,所以第一次沒(méi)有執(zhí)行if中的正放代碼是因?yàn)槠渲禐閚ull。解決方法是把定時(shí)器內(nèi)的匿名函數(shù)拿出來(lái),定時(shí)器內(nèi)調(diào)用函數(shù)名即可。)
打字機(jī)效果案例源碼:https://cloud.189.cn/t/MbYraiArERrq(訪問(wèn)碼:hzj6)
修復(fù)bug
下邊的方法已經(jīng)廢棄,有了更好的實(shí)現(xiàn)方法。已放到上邊。這里的方法也可以實(shí)現(xiàn)效果,但是過(guò)于凌亂。
其實(shí)bug并沒(méi)有修復(fù),而是使用了另一種方法來(lái)實(shí)現(xiàn)打字機(jī)效果。將正、倒放單獨(dú)作為一個(gè)函數(shù),不過(guò)在正放的函數(shù)結(jié)束后調(diào)用倒放的函數(shù)。再使用一個(gè)函數(shù)調(diào)用正放的函數(shù)。
-
正、倒放函數(shù),positive(element,str, time, timewait)、reverse(element,str, time, timewait)
-
各形參分別為:顯示文本的容器,顯示的文本,一個(gè)字符顯示時(shí)間,正倒放間隔時(shí)間
-
正、倒放函數(shù)都是在正、倒放操作的基礎(chǔ)上加一個(gè)定時(shí)器,添加等待時(shí)間
//倒放 setTimeout(function() {//內(nèi)部的實(shí)現(xiàn)代碼與前邊的一樣,并未修改for (let j = str.length; j >= 0; j--) { //倒放setTimeout(function() { //定時(shí)器element.innerHTML = str.substr(0, j);}, (str.length - j) * time);}}, timewait);//使用定時(shí)器增加等待時(shí)間 -
正放函數(shù)的后邊調(diào)用倒放函數(shù),計(jì)算好正放時(shí)間加等待時(shí)間后使用定時(shí)器調(diào)用
//正放 setTimeout(function() {for (let i = 1; i <= str.length; i++) { //正放setTimeout(function() { //定時(shí)器element.innerHTML = str.substr(0, i);}, (i - 1) * time);}//調(diào)用倒放setTimeout( 調(diào)用倒放 , 正放所用時(shí)間+等待時(shí)間 );}, timewait);//播放前的等待時(shí)間
-
-
調(diào)用正放的函數(shù),showText02(element, str, num,time,timewait),形參有:顯示文本的容器,顯示的文本,播放次數(shù)(正+倒為一次),一個(gè)字符顯示時(shí)間,正倒放間隔時(shí)間
- 使用for循環(huán),實(shí)現(xiàn)指定的播放次數(shù)。不過(guò)在調(diào)用正放函數(shù)時(shí)需要使用定時(shí)器。
- 可以將正放的函數(shù)看作是一次正放加倒放(正放后邊調(diào)用了倒放),所以定時(shí)器的時(shí)間可以設(shè)置為一次正放的時(shí)間+一次倒放的時(shí)間+兩個(gè)等待時(shí)間,即:str.length * time * 2 + timewait*2
- showText02有四個(gè)參數(shù),但是我們可以內(nèi)置字符顯示時(shí)間(200ms)、等待時(shí)間(2000ms)和播放次數(shù) (1次),使用時(shí)如果不想頻繁設(shè)置這些參數(shù),只需要給顯示文本的容器和要顯示的文本兩個(gè)參數(shù)即可。
使用:
//獲取文本顯示的span(顯示文本的容器) let word = document.querySelector('.word'); showText02(word,str,4);//顯示文本的容器、顯示的文本,播放次數(shù)(正+倒為一次),一個(gè)字符顯示時(shí)間,正倒放間隔時(shí)間實(shí)現(xiàn)打字機(jī)效果的一些函數(shù):
//實(shí)現(xiàn)方法2 function showText02(element,str, num,time,timewait) {//time,每個(gè)字符顯示的時(shí)間,建議200毫秒//timewait,正倒放等待時(shí)間,建議2000毫秒//num,播放次數(shù),默認(rèn)一次if(time == null){time = 200;}if(timewait == null){timewait = 2000;}if(num == null){num = 1;}for (var i = 0; i < num; i++) {//for循環(huán)控制播放次數(shù)setTimeout(function() {positive(element,str, time, timewait);}, (str.length * time * 2 + timewait*2) * i);//括號(hào)內(nèi)的時(shí)間為一次正加一次倒} } //正放 function positive(element,str, time, timewait) {setTimeout(function() {for (let i = 1; i <= str.length; i++) { //正放setTimeout(function() { //定時(shí)器element.innerHTML = str.substr(0, i);}, (i - 1) * time);}setTimeout(function() {reverse(element,str, time);}, str.length * time + timewait);//正放結(jié)束后再開(kāi)始倒放,使用定時(shí)器增加正放時(shí)間和結(jié)束后的等待時(shí)間}, timewait);//播放前的等待時(shí)間 } //倒放 function reverse(element,str, time, timewait) {setTimeout(function() {for (let j = str.length; j >= 0; j--) { //倒放setTimeout(function() { //定時(shí)器element.innerHTML = str.substr(0, j);}, (str.length - j) * time);}}, timewait);//使用定時(shí)器增加等待時(shí)間 }完整源代碼如下:
<!DOCTYPE html> <html><head><meta charset="utf-8" /><title>qsdbl</title></head><body><div class="text"><span class="word"></span><span class="gbiao">|</span></div></body><style type="text/css">* {margin: 0;padding: 0;}body {height: 100vh;/*讓文本居中*/display: flex;align-items: center;justify-content: center;/*徑向漸變*/background: radial-gradient(#000000, rgb(64, 204, 15));}.text {color: #fff;/*0f0*/text-align: center;font-size: 40px;font-weight: bold;}.text .gbiao {margin-left: 5px;animation: flash 0.5s linear infinite;/*讓光標(biāo)閃爍*/}@keyframes flash {from {opacity: 0;}to {opacity: 1;}}</style><style type="text/css">/*當(dāng)顯示設(shè)備為手機(jī)時(shí),字體大小設(shè)置為20px。(用于判斷設(shè)備類型的500px是一個(gè)經(jīng)驗(yàn)值)*/@media(max-width:500px) {.text {font-size: 20px;}}</style><script>let str = "你好,我是輕率的保羅!很高興見(jiàn)到你!"; //要顯示的文本//獲取文本顯示的span(顯示文本的容器)let word = document.querySelector('.word');//播放4次showText02(word,str,4);//顯示文本的容器,顯示的文本,播放次數(shù)(正+倒為一次),一個(gè)字符顯示時(shí)間,正倒放間隔時(shí)間//實(shí)現(xiàn)打字機(jī)效果(下邊為封裝的函數(shù))function showText02(element,str, num,time,timewait) {//time,每個(gè)字符顯示的時(shí)間,建議200毫秒//timewait,正倒放等待時(shí)間,建議2000毫秒if(time == null){time = 200;}if(timewait == null){timewait = 2000;}if(num == null){num = 1;}for (var i = 0; i < num; i++) {//for循環(huán)控制播放次數(shù)setTimeout(function() {positive(element,str, time, timewait);}, (str.length * time * 2 + timewait*2) * i);//括號(hào)內(nèi)的時(shí)間為一次正加一次倒}}//正放function positive(element,str, time, timewait) {setTimeout(function() {for (let i = 1; i <= str.length; i++) { //正放setTimeout(function() { //定時(shí)器element.innerHTML = str.substr(0, i);}, (i - 1) * time);}setTimeout(function() {reverse(element,str, time);}, str.length * time + timewait);//正放結(jié)束后再開(kāi)始倒放,使用定時(shí)器增加正放時(shí)間和結(jié)束后的等待時(shí)間}, timewait);//播放前的等待時(shí)間}//倒放function reverse(element,str, time, timewait) {setTimeout(function() {for (let j = str.length; j >= 0; j--) { //倒放setTimeout(function() { //定時(shí)器element.innerHTML = str.substr(0, j);}, (str.length - j) * time);}}, timewait);//使用定時(shí)器增加等待時(shí)間}</script> </html>原文鏈接:實(shí)現(xiàn)打字機(jī)特效
總結(jié)
- 上一篇: 【sequoiadb|巨杉数据库】创建数
- 下一篇: python高级编程之网络编程