Vue+ElementUI: 手把手教你作一個audio組件

目的

  • 本項目的目的是教你如何實現一個簡單的音樂播放器(這並不難)
  • 本項目並非一個能夠用於生產環境的element播放器,因此並無考慮太多的兼容性問題
  • 本項目不是ElementUI的一個音頻插件,只是一個教程,不過你能夠自行擴展實現
  • 本項目只是爲了學習audio相關事件以及API

本項目的音頻文件是位於static/falling-star.mp3,歌曲名爲:星球墜落Live 艾熱、李佳隆css

運行

cd element-aduio && yarn && yarn run dev

文檔

1. 簡介

1.1 相關技術

1.2 從本教程你會學到什麼?

  • Vue單文件組件開發知識
  • Element UI基本用法
  • Audio原生API及Audio相關事件
  • 音頻播放器的基本原理
  • 音頻的播放暫停控制
  • 音頻顯示時間
  • 音頻進度條控制與跳轉
  • 音頻音量控制
  • 音頻播放速度控制
  • 音頻靜音控制
  • 音頻下載控制
  • 個性化配置與排他性播放
  • 一點點ES6語法

1.3 學前準備

基本上不須要什麼準備,可是若是你能先看一下Aduio相關API和事件將會更好vue

1.4 在線demo

沒有在線demo的教程都是耍流氓webpack

2 開始編碼

2.1 項目初始化

➜  test vue init webpack element-audio

  A newer version of vue-cli is available.

  latest:    2.9.2
  installed: 2.9.1

? Project name element-audio
? Project description A Vue.js project
? Author wangdd <wangdd@xxxxxx.com>
? Vue build standalone
? Install vue-router? No
? Use ESLint to lint your code? No
? Set up unit tests No
? Setup e2e tests with Nightwatch? No
? Should we run `npm install` for you after the project has been created? (recommended) npm

➜  test cd element-audio 
➜  element-audio npm run dev

瀏覽器打開 http://localhost:8080/, 看到以下界面,說明項目初始化成功ios

圖片1git

2.2 安裝ElementUI並插入audio標籤

2.2.1 安裝ElementUI

yarn add element-ui // or npm i element-ui -S

2.2.2 在src/main.js中引入Element UI

// filename: src/main.js
import Vue from 'vue'
import ElementUI from 'element-ui'
import App from './App'
import 'element-ui/lib/theme-chalk/index.css'

Vue.config.productionTip = false

Vue.use(ElementUI)

/* eslint-disable no-new */
new Vue({
  el: '#app',
  template: '<App/>',
  components: { App }
})

2.2.3 建立src/components/VueAudio.vue

// filename: src/components/VueAudio.vue
<template>
  <div>
    <audio src="http://devtest.qiniudn.com/secret base~.mp3" controls="controls"></audio>
  </div>
</template>

<script>
export default {
  data () {
    return {}
  }
}
</script>

<style>

</style>

2.2.4 修改src/App.vue, 並引入VueAudio.vue組件

// filename: src/App.vue
<template>
  <div id="app">
    <VueAudio />
  </div>
</template>

<script>
import VueAudio from './components/VueAudio'

export default {
  name: 'app',
  components: {
    VueAudio
  },
  data () {
    return {}
  }
}
</script>

<style>

</style>

打開:http://localhost:8080/,你應該能看到以下效果,說明引入成功,你能夠點擊播放按鈕看看,音頻是否可以播放
圖2github

2.3 音頻的播放暫停控制

咱們須要用一個按鈕去控制音頻的播放與暫停,這裏調用了audio的兩個api,以及兩個事件web

  • audio.play()
  • audio.pause()
  • play事件
  • pause事件

修改src/components/VueAudio.vuevue-router

// filename: src/components/VueAudio.vue
<template>
  <div>
    <!-- 此處的ref屬性,能夠很方便的在vue組件中經過 this.$refs.audio獲取該dom元素 -->
    <audio ref="audio" 
    @pause="onPause"
    @play="onPlay"
    src="http://devtest.qiniudn.com/secret base~.mp3" controls="controls"></audio>

    <!-- 音頻播放控件 -->
    <div>
      <el-button type="text" @click="startPlayOrPause">{{audio.playing | transPlayPause}}</el-button>
    </div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      audio: {
        // 該字段是音頻是否處於播放狀態的屬性
        playing: false
      }
    }
  },
  methods: {
    // 控制音頻的播放與暫停
    startPlayOrPause () {
      return this.audio.playing ? this.pause() : this.play()
    },
    // 播放音頻
    play () {
      this.$refs.audio.play()
    },
    // 暫停音頻
    pause () {
      this.$refs.audio.pause()
    },
    // 當音頻播放
    onPlay () {
      this.audio.playing = true
    },
    // 當音頻暫停
    onPause () {
      this.audio.playing = false
    }
  },
  filters: {
    // 使用組件過濾器來動態改變按鈕的顯示
    transPlayPause(value) {
      return value ? '暫停' : '播放'
    }
  }
}
</script>

<style>

</style>

圖3 音頻播放與暫停vue-cli

2.4 音頻顯示時間

音頻的時間顯示主要有兩部分,音頻的總時長和當前播放時間。能夠從兩個事件中獲取npm

  • loadedmetadata:表明音頻的元數據已經被加載完成,能夠從中獲取音頻總時長
  • timeupdate: 當前播放位置做爲正常播放的一部分而改變,或者以特別有趣的方式,例如不連續地改變,能夠從該事件中獲取音頻的當前播放時間,該事件在播放過程當中會不斷被觸發

要點代碼:整數格式化成時:分:秒

function realFormatSecond(second) {
  var secondType = typeof second

  if (secondType === 'number' || secondType === 'string') {
    second = parseInt(second)

    var hours = Math.floor(second / 3600)
    second = second - hours * 3600
    var mimute = Math.floor(second / 60)
    second = second - mimute * 60

    return hours + ':' + ('0' + mimute).slice(-2) + ':' + ('0' + second).slice(-2)
  } else {
    return '0:00:00'
  }
}

要點代碼: 兩個事件的處理

// 當timeupdate事件大概每秒一次,用來更新音頻流的當前播放時間
onTimeupdate(res) {
      console.log('timeupdate')
      console.log(res)
      this.audio.currentTime = res.target.currentTime
    },
// 當加載語音流元數據完成後,會觸發該事件的回調函數
// 語音元數據主要是語音的長度之類的數據
onLoadedmetadata(res) {
  console.log('loadedmetadata')
  console.log(res)
  this.audio.maxTime = parseInt(res.target.duration)
}

完整代碼

<template>
  <div>
    <!-- 此處的ref屬性,能夠很方便的在vue組件中經過 this.$refs.audio獲取該dom元素 -->
    <audio ref="audio" 
    @pause="onPause"
    @play="onPlay"
    @timeupdate="onTimeupdate" 
    @loadedmetadata="onLoadedmetadata"
    src="http://devtest.qiniudn.com/secret base~.mp3" controls="controls"></audio>

    <!-- 音頻播放控件 -->
    <div>
      <el-button type="text" @click="startPlayOrPause">{{audio.playing | transPlayPause}}</el-button>

      <el-tag type="info">{{ audio.currentTime | formatSecond}}</el-tag>

      <el-tag type="info">{{ audio.maxTime | formatSecond}}</el-tag>
    </div>
  </div>
</template>

<script>

// 將整數轉換成 時:分:秒的格式
function realFormatSecond(second) {
  var secondType = typeof second

  if (secondType === 'number' || secondType === 'string') {
    second = parseInt(second)

    var hours = Math.floor(second / 3600)
    second = second - hours * 3600
    var mimute = Math.floor(second / 60)
    second = second - mimute * 60

    return hours + ':' + ('0' + mimute).slice(-2) + ':' + ('0' + second).slice(-2)
  } else {
    return '0:00:00'
  }
}

export default {
  data () {
    return {
      audio: {
        // 該字段是音頻是否處於播放狀態的屬性
        playing: false,
        // 音頻當前播放時長
        currentTime: 0,
        // 音頻最大播放時長
        maxTime: 0
      }
    }
  },
  methods: {
    // 控制音頻的播放與暫停
    startPlayOrPause () {
      return this.audio.playing ? this.pause() : this.play()
    },
    // 播放音頻
    play () {
      this.$refs.audio.play()
    },
    // 暫停音頻
    pause () {
      this.$refs.audio.pause()
    },
    // 當音頻播放
    onPlay () {
      this.audio.playing = true
    },
    // 當音頻暫停
    onPause () {
      this.audio.playing = false
    },
    // 當timeupdate事件大概每秒一次,用來更新音頻流的當前播放時間
    onTimeupdate(res) {
      console.log('timeupdate')
      console.log(res)
      this.audio.currentTime = res.target.currentTime
    },
    // 當加載語音流元數據完成後,會觸發該事件的回調函數
    // 語音元數據主要是語音的長度之類的數據
    onLoadedmetadata(res) {
      console.log('loadedmetadata')
      console.log(res)
      this.audio.maxTime = parseInt(res.target.duration)
    }
  },
  filters: {
    // 使用組件過濾器來動態改變按鈕的顯示
    transPlayPause(value) {
      return value ? '暫停' : '播放'
    },
    // 將整數轉化成時分秒
    formatSecond(second = 0) {
      return realFormatSecond(second)
    }
  }
}
</script>

<style>

</style>

打開瀏覽器能夠看到,當音頻播放時,當前時間也在改變。
圖4

2.5 音頻進度條控制

進度條主要有兩個控制,改變進度的原理是:改變audio.currentTime屬性值

  • 音頻播放後,當前時間改變,進度條就要隨之改變
  • 拖動進度條,能夠改變音頻的當前時間
// 進度條ui
<el-slider v-model="sliderTime" :format-tooltip="formatProcessToolTip" @change="changeCurrentTime" class="slider"></el-slider>

// 拖動進度條,改變當前時間,index是進度條改變時的回調函數的參數0-100之間,須要換算成實際時間
changeCurrentTime(index) {
  this.$refs.audio.currentTime = parseInt(index / 100 * this.audio.maxTime)
},
// 當音頻當前時間改變後,進度條也要改變
onTimeupdate(res) {
  console.log('timeupdate')
  console.log(res)
  this.audio.currentTime = res.target.currentTime
  this.sliderTime = parseInt(this.audio.currentTime / this.audio.maxTime * 100)
},

// 進度條格式化toolTip
formatProcessToolTip(index = 0) {
  index = parseInt(this.audio.maxTime / 100 * index)
  return '進度條: ' + realFormatSecond(index)
},

2.6 音頻音量控制

音頻的音量控制和進度控制差很少,也是經過拖動滑動條,去修改aduio.volume屬性值,此處再也不囉嗦

2.7 音頻播放速度控制

音頻的音量控制和進度控制差很少,也是點擊按鈕,去修改aduio.playbackRate屬性值,該屬性表明音量的大小,取值範圍是0 - 1,用滑動條的時候,也是須要換算一下值,此處再也不囉嗦

2.8 音頻靜音控制

靜音的控制是點擊按鈕,去修改aduio.muted屬性,該屬性有兩個值: true(靜音),false(不靜音)。 注意,靜音的時候,音頻的進度條仍是會繼續往前走的。

2.9 音頻下載控制

音頻下載是一個a連接,記得加上download屬性,否則瀏覽器會在新標籤打開音頻,而不是下載音頻

<a :href="url" v-show="!controlList.noDownload" target="_blank" class="download" download>下載</a>

2.10 個性化配置

音頻的個性化配置有不少,你們能夠本身擴展,經過父組件傳遞響應的值,能夠作到個性化設置。

controlList: {
  // 不顯示下載
  noDownload: false,
  // 不顯示靜音
  noMuted: false,
  // 不顯示音量條
  noVolume: false,
  // 不顯示進度條
  noProcess: false,
  // 只能播放一個
  onlyOnePlaying: false,
  // 不要快進按鈕
  noSpeed: false
}

setControlList () {
    let controlList = this.theControlList.split(' ')
    controlList.forEach((item) => {
      if(this.controlList[item] !== undefined){
        this.controlList[item] = true
      }
    })
},

例如父組件這樣

<template>
  <div id="app">
    <div v-for="item in audios" :key="item.url">
      <VueAudio :theUrl="item.url" :theControlList="item.controlList"/>
    </div>
  </div>
</template>

<script>
import VueAudio from './components/VueAudio'

export default {
  name: 'app',
  components: {
    VueAudio
  },
  data () {
    return {
      audios: [
        {
          url: 'http://devtest.qiniudn.com/secret base~.mp3',
          controlList: 'onlyOnePlaying'
        },
        {
          url: 'http://devtest.qiniudn.com/回レ!雪月花.mp3',
          controlList: 'noDownload noMuted onlyOnePlaying'
        },{
          url: 'http://devtest.qiniudn.com/あっちゅ~ま青春!.mp3',
          controlList: 'noDownload noVolume noMuted onlyOnePlaying'
        },{
          url: 'http://devtest.qiniudn.com/Preparation.mp3',
          controlList: 'noDownload noSpeed onlyOnePlaying'
        }
      ]
    }
  }
}
</script>

<style>

</style>

2.11 一點點ES6語法

大多數時候,咱們但願頁面上播放一個音頻時,其餘音頻能夠暫停。
[...audios]能夠把一個類數組轉化成數組,這個是我經常使用的。

onPlay (res) {
    console.log(res)
    this.audio.playing = true
    this.audio.loading = false
    
    if(!this.controlList.onlyOnePlaying){
      return 
    }
    
    let target = res.target
    
    let audios = document.getElementsByTagName('audio');
    // 若是設置了排他性,當前音頻播放是,其餘音頻都要暫停
    [...audios].forEach((item) => {
      if(item !== target){
        item.pause()
      }
    })
},

感謝

  • 若是你須要一個小型的vue音樂播放器,你能夠試試vue-aplayer, 該播放器不單單支持vue組件,非Vue的也支持,你能夠看看他們的demo
相關文章
相關標籤/搜索