打字機效果文字插件typer.js
typer.js介紹
typer.js是模擬打字機效果的輕型js插件(1.6 Kb),有打字、刪除、重複和停頓幾種簡單的效果。
起因
由於這幾天寫個在線簡歷,我想使用打字的特效,在github上搜到一個叫TheaterJS的插件,效果很好,但是應用時發現,TheaterJS開發版的體積近80kb,而且我只需要它的打字機效果,不需其他複雜的功能,於是又萌生了自己造輪子的想法。
構思
之前寫的listen2me用過類似的文字單播的效果,加上見過許多其他打字機效果,心裏覺得還是有底的。
想了想自己的需求,效果上分爲兩塊:
- 文字逐個顯示
- 閃爍的光標
在使用上需要:
- 輸出內容控制簡便,模仿TheaterJs輸出時的鏈式調用方法。
- 控制速度、停頓等
研究過程
一些錯誤的想法
打字效果很簡單,簡單的JS代碼配合CSS就很好的還原了TheaterJS的效果,當然這僅是一行文字的輸出。
然後研究輸出控制。剛開始單純的以爲借用JQUERY可以直接鏈式調用與事件的順序執行,具體寫代碼才發現,jquery的鏈式調用是操作節點的,而且它的內置函數應該都設定好了對鏈式操作的支持,我在網上查閱了一些資料,js可以通過對函數return this來支持鏈式調用。
又研究了事件的順序,同樣,本以爲jquery的鏈式調用可以按順序執行,比如$('DOM').fadeIn().fadeOut().animate(....)
這個操作就是按照淡入、淡出再動畫的順序進行的,後面的操作會等待前面的完成。寫代碼時又發現,我寫的js無法以這個思路實現按序執行,因爲打字效果要使用setTimeout
這個函數,使得整個過程成爲異步,JS執行時自然無法有序。看了一些JQUERY代碼,發現除了鏈式調用外,可以按序執行代碼的方法還有使用callback
,比如``$('DOM').animate({'width':'100%'},1000,function(){........})
。
然後自己陷入了混亂,再亂試了各種方法之後,選擇了睡覺。
今天早起,突然就想清楚昨天嘗試的方法問題在哪裏,比如這段事件等待:
while (!isTyping) {
this.isTyping = true;
speed = speed ? speed : this.speed;
var duration = text.length * speed;
var set = function() {
isTyping = true;
}
for (var i = 0; i < text.length; i++) {
setTimeout(addText, speed * i, text.charAt(i));
setTimeout(function() {
isTyping = false;
}, duration);
set()
}
}
用while其實是個死循環。
我的本意是建立一個isTyping標誌,當第一個打字事件開始時,isTyping爲true,這樣第二個事件會因爲while的條件不成立,一直在空轉等待前一個事件完成時isTyping爲false。但是,第一個事件完成時,isTyping爲false的瞬間,仍是在while循環體內,又觸發了while (!isTyping),所以永遠都輪不到第二個事件,永遠都停在了第一個事件內。
正確的思路
事件的順序
繼而決定使用想到的第二種思路,將所有的打字事件,計算出所消耗的時間,使用setTimeout
將每個事件用時累加起來,作爲下一個事件的開始事件,也就是說:
a事件: typer.type('this is the first paragraph')
b事件: typer.type('this is the second paragraph')
.....
n事件: typer.type('this is the first paragraph')
a事件需要比如10s,那麼b事件的開始時間就是10s後,也就是setTimeout(b事件,10000)
,依次類推,這樣所有的打字事件都可以由setTimeout
控制其順序了。
鏈式調用
再給每個type
函數加上return this,這樣就可以鏈式調用了:
var babyTyper = new typer(DOM);
babyTyper
.type('I am a babyTyper')
.type('and I love typing in this way')
.type('I feel so happy!')
或者這樣
babyTyper.type('I am brother of that guy,').type(' I love typing in a row, ').type('because it is cool!')
閃爍的打字光標效果
剛開始研究效果時,使用過INPUT
輸入框,去除邊框border
和outlook
後,只需獲得輸入焦點,JS將文字輸入到input即可,同樣是打字的效果,但是有一點不足,無法控制閃爍光標的樣式,因爲這個光標是繼承自系統的,無論怎麼調節CSS字體樣式,光標都是那麼細小,跳動的頻率也控制不了。
這裏就借鑑了TheaterJS的方法,使用::after
僞元素給內容加入一個動畫內容:
.typer-place::after {
content: '|';
animation: blink 800ms infinite;
}
@keyframes blink {
from { opacity: 0; }
to { opacity: 1; }
}
這樣就實現了打字時閃爍光標的效果。
循環重複
功能都完成後,我又想到需要一個循環播放的功能。想了一會,想到一個最基礎的方法,就是建立一個記錄操作的方法,把每次的輸出與刪除都按順序記錄。然後再把記錄的內容再次執行就可以。看了幾個源碼,他們寫的重複也是記錄操作再次執行。
但是我總覺得這樣太麻煩,不夠簡便,不如想一種方法無需記錄,直接重複。查閱了些資料,好像沒有什麼現成的例子重複執行代碼的,最終寫成如下:
var typer = new typer(DOM);
setInterval(repeat,typer.duration)
function repeat(){
typer.type('測試')
typer.type('測試')
typer.type('測試')
}
這個邏輯很清晰,我很喜歡,但是寫出來的內容太多了,不夠簡潔。最終我還是選擇了記錄操作,實現重複只需一個方法typer.repeat()
。
以上幾點是代碼的關鍵部分,完成之後,其餘的內容都相對簡單,很快就處理完了。
源碼及使用
源碼在我的github
使用方法很簡單
<script src="typer.js"></script>
<script>
var typer = new typer('DOM的ID'))
typer.type('hi~')
typer.type('當然也可以按照鏈式調用那樣省略typer')
</script>
具體使用方法參見github readme
小結
總體來講,就是打字事件按順序調用和尋找簡便重複方法這兩部分想的挺久的,其餘都很簡單。