Vue.jsでループ中に登場するオーディオの再生・停止ボタンを音源ごとに動的に切り替えたい。
↑作りたいもの(大体の感じ)
・オーディオタグが複数存在する
・再生ボタンを押したら、再生中の音源のボタンだけ停止ボタンに切り替えたい
オーディオファイルが1つだけなら、再生中か停止中かのフラグを持たせてv-ifで切り替えるだけでいい。
しかし、そのやり方の場合複数のオーディオファイルがあると全部のオーディオの隣のボタンが同時に停止ボタンに変化してしまう。
個別に動作させるには、
v-if="(playingNow==再生中のオーディオのID")
をvueで仕込んであげればいい。
今回は、波形表示オーディオライブラリ「av-waveformav-waveform」を使った例を参考に解説する。
今回の環境
・オーディオを波形あり表示にしてくれるライブラリ「vue-audio-visual」を利用
・vue2
・CSSフレームワーク「bootstrap vue」を利用
・バックエンドはLaravel8(別に何でもいい)
https://github.com/staskobzar/vue-audio-visual
導入方法についてはこの記事では割愛する。
データベース設計
stocksテーブル
今回の例ではIDとfilenameしか使わない。
フロントのhtml部分
//Audios.vue
<span v-for="(stock) in stocks" :key="stock.id">
<div class="d-flex flex-nowrap bd-highlight">
<b-col cols="1" class="valign-center">
<b-button v-if="playingNow==stock.id" :id="'button'+stock.id" @click="stop(stock.id)">
<font-awesome-icon :icon="['fa', 'stop']" />
</b-button>
<b-button v-else :id="'button'+stock.id" @click="play(stock.id)">
<font-awesome-icon :icon="['fa', 'play']" />
</b-button>
</b-col>
<b-col cols="3" class="scroll-child">
<av-waveform class="player" :id="'audio'+stock.id"
:audio-src="'/storage/stock_sample/'+stock.filename+'.mp3'" playtime-slider-color="white"
:canv-width="waveWidth" played-line-color="black" :playtime="false"
noplayed-line-color="#bababa">
</av-waveform>
</b-col>
</div>
</span>
この例では、CSSフレームワークbootstrap vueとアイコンライブラリfontawesome4を利用している。
5行目のv-if="playingNow==stock.id"
が重要。
再生中のオーディオのIDがループ中の自分自身を表すのであれば、ボタンが再生ボタンから停止ボタンに変化することを想定している。
↓
<av-waveform class="player" :id="'audio'+stock.id"> ・・・</av-waveform>
が今回で言うところのオーディオタグにあたる。
srcにオーディオファイルのパスさせ仕込めれば、
別に普通のオーディオタグを使ってくれてもOK。
で、
これだけじゃ動かないので、javascriptについても解説。
フロントのjavascript部分
//Audios.vue
<script>
data() {
return {
stocks: null, //曲一覧のレコ―ド軍が格納される変数
beforePlaying: null, //直近で再生していた曲
playingNow: null, //再生中の曲
playing:false, //今は曲を再生中かどうか
}
},
methods: {
play(stockId) {
if (this.beforePlaying) {
//直近で再生した音源を停止
this.beforePlaying.pause()
}
let audio = document.getElementById('audio' + stockId).children.item(0).children.item(0)
this.playing = true//オーディオを再生中フラグ(いらんかも)
this.playingNow = stockId //再生中のオーディオのID
audio.play()
this.beforePlaying = audio
},
stop(stockId) {
let audio = document.getElementById('audio' + stockId).children.item(0).children.item(0)
audio.pause()
this.playing = false //オーディオ停止中フラグ(いらんかも)
this.playingNow = null //再生中のオーディオはない
},
}
};
</script>
play()
メソッドで、受け取ったオーディオのIDをplayingNow
に格納ている。
さらにメソッドの終わりに、this.beforePlaying = audio
と宣言することにより
・最後に再生されていたオーディオはこれです!
・次回playメソッドが走った際には、そのオーディオをまず停止する!
という動きが可能になっている。
stop()
メソッドでは、引数として受け取ったIDのオーディオタグの再生を停止させ、
playingNow = null
とすることにより、ボタンが停止ボタンから再生ボタンに戻る仕組みになっている。
今回のCSS
環境によるので、別に参考にしなくてもいい。
//Audios.vue
.valign-center {
display: flex;
justify-content: center;
align-items: center;
}
/* av-waveformのオーディオだけ表示したいので、
同時に表示されてしまう元々のオーディオプレイヤーを非表示に
*/
::v-deep audio {
display: none;
}