サウンドノベルっぽいテキストアニメーションをJSで実現したい。
どういう動きかというとこんな感じ↓
ライブラリはいくつかあるのだけれども、やりたいことをすべて叶えてくれるものはなかった…ので、書きました。
やりたいこと
- 指定したテキストが1文字ずつ表示される
- 表示途中でクリックすると全文表示される
- 表示完了後にクリックすると次のテキストの表示を開始する
- 複数のJSから上記の共通処理を呼び出す
完成形
元はviteで書いていたコードを単純jsっぽく直したので整合性取れていないところがあるかもしれませんが…こんな感じになりました。
TypeWriter.js
/*
TypeWriter
呼び出し元で1つインスタンスを生成して使用
*/
export const TypeWriter = class {
constructor(query) {
this.charNum = 0
this.textWriteEnd = false
this.el = document.querySelector(query)
}
print(text) {
this.textWriteEnd = false
this.charNum = 0
this.el.textContent = ''
const self = this
self._print(text.split(''))
}
_print(chars) {
const self = this
const timer = setTimeout(() => { self._print(chars) }, 50)
if (this.charNum < chars.length) {
this.el.textContent += chars[this.charNum]
this.charNum++
if (this.charNum === chars.length) {
this.textWriteEnd = true
}
} else {
clearTimeout(timer)
this.textWriteEnd = true
}
}
printAll(text) {
this.charNum = text.split('').length + 1
this.el.textContent = text
}
}
sample.js
import { TypeWriter } from '/js/typewriter.js'
let page = 0
let tw
let clickable = false
const textList = [
{ txt: 'テキスト1' },
{ txt: 'テキスト2' },
]
window.onload = () => {
tw = new TypeWriter('#id') // テキスト描画したい要素
setTimeout(() => {
tw.print(textList[page].txt)
clickable = true
}, 500)
}
// クリックイベント
const goNext = () => {
if (!clickable) return
if (tw.textWriteEnd) {
page++
if (page < textList.length) {
tw.print(textList[page].txt)
} else {
// URL遷移
}
} else {
tw.printAll(textList[page].txt)
}
}
おすすめライブラリ
もっとシンプルで良いのなら、iTyped.jsがおすすめです。
今回は「途中クリックで全文表示」という要件が出た時点で使えなくなりました(泣)
参考にさせていただいたサイト
あとがき
jsはなんとなくでずっといじっていて、今回初めてclassを使いました。
多分美しくないコードだと思います。
ご指摘やアドバイスは歓迎いたします。