typer.js,可能是最小但功能也不多的模擬打字效果插件

打字機效果文字插件typer.js


typer.js介紹

typer.js是模擬打字機效果的輕型js插件(1.6 Kb),有打字、刪除、重複和停頓幾種簡單的效果。

起因

由於這幾天寫個在線簡歷,我想使用打字的特效,在github上搜到一個叫TheaterJS的插件,效果很好,但是應用時發現,TheaterJS開發版的體積近80kb,而且我只需要它的打字機效果,不需其他複雜的功能,於是又萌生了自己造輪子的想法。

構思

之前寫的listen2me用過類似的文字單播的效果,加上見過許多其他打字機效果,心裏覺得還是有底的。

想了想自己的需求,效果上分爲兩塊:

  1. 文字逐個顯示
  2. 閃爍的光標

在使用上需要:

  1. 輸出內容控制簡便,模仿TheaterJs輸出時的鏈式調用方法。
  2. 控制速度、停頓等

研究過程

一些錯誤的想法

打字效果很簡單,簡單的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輸入框,去除邊框borderoutlook後,只需獲得輸入焦點,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

typer.js

使用方法很簡單

<script src="typer.js"></script>
<script>
  var typer = new typer('DOM的ID'))
  typer.type('hi~')
  typer.type('當然也可以按照鏈式調用那樣省略typer')
</script>

具體使用方法參見github readme

小結

總體來講,就是打字事件按順序調用和尋找簡便重複方法這兩部分想的挺久的,其餘都很簡單。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章