移动端使用audio出现的兼容性问题

1,133 阅读1分钟

前言

前端开发中经常会遇到实现播放音频文件的需求,本文基于mintUI封装了一个音频播放组件。

features

  • 支持播放、暂停、拖动播放的功能
  • 良好的移动端播放体验
  • 兼容android和ios主流系统
  • 兼容webview

sourceCode

	<template>
      <div>
        <div class="audio-play-wrapper">
          <i class="operate-container" :class="[isPlay ? 'pause' : '']" @click.stop="audioState($event)"></i>
          <div class="time-info-container change-time">
            <span class="task-text vm current-time">{{ stopTime }}</span>
          </div>
          <div class="time-progress-container">
            <mt-range
                    :min="0"
                    :max="audioDuration"
                    :bar-height="8"
                    v-model="currentTime"
                    @change="processMove"
            ></mt-range>
          </div>
          <div class="time-info-container">
            <span class="task-text vm current-time">{{ audioDuration | formatTime }}</span>
          </div>
          <audio @error="errorHandler" @loadedmetadata="loadAudioMetaData" @canplay="getDuration" class="audio" ref="iAudio" :src="audioInfo.audioUrl"></audio>
        </div>
      </div>
</template>

<script>
  import { formatSeconds } from "@/utils/index";
  import { Toast } from "mint-ui";

  export default {
    name: "AudioPlayMedia",
    components: {},
    props: {
      audioInfo: {
        type: Object,
        default: () => {
          return {
            audioUrl:
              "",
          };
        },
      },
    },
    data() {
      return {
        isPlay: false,
        currentTime: 0,
        audioDuration: 0,
        isIphone6: false,
        isVertical:!window.isTablet,
      };
    },
    created: function () {
      // 解决ios10.0.1获取音频时长加倍的问题
      let u = navigator.userAgent;
      if(window.isIOS &&
        navigator.userAgent.toLowerCase().indexOf("iphone os 10_0_1") != -1 &&
        navigator.userAgent.toLowerCase().indexOf("iphone 6") != -1) {
        this.isIphone6 = true;
      }
    },
    mounted() {
    },
    computed: {
      stopTime: function () {
        return formatSeconds(this.currentTime);
      },
    },
    filters: {
      formatTime(time) {
        return formatSeconds(time);
      }
    },
    methods: {
      audioState: function (event) {
        if (this.isPlay) {
          this.isPlay = !this.isPlay;
          let audio = this.$refs.iAudio;
          audio.pause();
          return;
        }
        this.$eventBus.$emit("audioStateChanged",event.target.id);
        // 点击播放或暂停
        let _this = this;
        _this.isPlay = !_this.isPlay;
        let audio = this.$refs.iAudio;
        if (this.isPlay) {
          audio.addEventListener("ended", function () {
            _this.isPlay = false;
          });
          audio.addEventListener("timeupdate", function (currentValue) {
            _this.currentTime = Math.ceil(_this.$refs.iAudio.currentTime);
          });
          audio.play();
        }
      },
      // 暂停音频
      pauseAudio: function(id) {
        if (id !== this.audioInfo.audioUrl) {
          this.isPlay = false;
          let audio = this.$refs.iAudio;
          audio.pause();
        }
      },
      processMove: function (time) {
        // 拖动进度条
        let audio = this.$refs.iAudio;
        audio.currentTime = time;
        this.currentTime = time;
      },
      getDuration:function() {
      },
      loadAudioMetaData: function() {
        let mDuration = this.$refs.iAudio.duration;
        this.audioDuration = Math.ceil(this.isIphone6 ? mDuration / 2: mDuration);
      },
      errorHandler: function() {
      }
    },
    destroyed() {},
  };
</script>

<style lang="scss" scoped>
  /**音频播放器样式 */
  .audio-play-container {
    padding: rem(23px) rem(36px);
    border-radius: rem(11px);
    border: 1px solid #f0f1f4;
    .audio-play-wrapper {
      display: flex;
      align-items: center;
      justify-content: space-between;
      .operate-container {
        display: inline-block;
        width: rem(60px);
        height: rem(60px);
        background: url("../../../assets/images/answer/audio-play.png") no-repeat
        center;
        background-size: contain;
        &.pause {
          background: url("../../../assets/images/answer/pause.png") no-repeat
          center;
          background-size: contain;
        }
      }
      .operate-container-across {
        width: rem(40px);
        height: rem(40px);
      }
      .time-progress-container {
        flex: 1;
        margin: 0px rem(24px);
      }
      .time-info-container {
        color: #8c8c8c;
        font-size: rem(24px);
        &.change-time {
          margin-left: rem(32px);
        }
      }
    }
    .current-time {
      font-size: 16px;
    }
  }
  .audio-play-container-across {
    padding: rem(16px) rem(36px);
  }
</style>
<style lang="scss">
  // mt-range控件样式
  .time-progress-container {
    .mt-range {
      .mt-range-content {
        .mt-range-runway {
          border-radius: 4px;
          border-top-color: #f0f1f4;
          right: -10px;
        }
        .mt-range-progress {
          background-color: #00baff;
          border-top-left-radius: 4px;
          border-bottom-left-radius: 4px;
        }
        .mt-range-thumb {
          top: 50%;
          transform: translateY(-50%);
          width: 12px;
          height: 12px;
          background: rgba(255, 255, 255, 1);
          box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0);
          border: 1px solid rgba(0, 186, 255, 1);
        }
      }
    }
  }
</style>

存在的问题

  • 在ihone的10.0.1系统上获取的音频总时长是真实时长的两倍(很诡异)
  • mt-range只支持拖曳快进,不支持点击快进
  • el-slider支持点击快进,不支持拖曳快进

音频播放的兼容性问题


参考文章

video中常用的事件