nuxt.js框架中 audio标签的坑

2019-12-04 09:49:05

爬坑地址 nuxt.js框架中 audio标签的坑

一、前言

上星期接到一个需求,业主说要在移动端的考试系统中弄一个背景音乐上去,让人听着做题更舒服,并且做对题目和做错题目都需要有不同的音乐提示(业主不当产品经理留在小公司折磨我这种小员工实属浪费)。于是就想到用html5的audio标签。但是后来做的时候发现,audio标签在IOS(苹果)端的微信浏览器中存在着很多坑,而且要整合到nuxt.js当中又踩了坑,决定把这些坑和解决办法记下来。


二、第一坑——nuxt.config.js的配置

本以为直接放audio标签进去.vue文件中就完事了,结果报了下图的错。




明知道是缺了某个loader,但是又不知道怎么配置,后来参照着vue-cli对mp3的配置,如下图




这里不作多说,参照着这个配置,我在nuxt.config.js文件中配置了对mp3文件的处理方法


build: {

    /*

    ** You can extend webpack config here

    */

    extend (config, ctx) {

      // Run ESLint on save

      const vueLoader = config.module.rules.find((loader) => loader.loader === 'vue-loader');

     /* 把audio标签在编译时转成src属性 */

      vueLoader.options.transformToRequire = {

        audio: 'src'

      };

      /* 对mp3等格式的文件用url-loader进行处理 */

      config.module.rules.push({

        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,

        loader: 'url-loader',

        options: {

          limit: 10000,

          name: process.env.NODE_ENV === 'production'

            ? path.posix.join('./', 'media/[name].[hash:7].[ext]')

            : path.posix.join('./', 'media/[name].[hash:7].[ext]')

        }

      });

      if (ctx.isDev && ctx.isClient) {

        config.module.rules.push({

          enforce: 'pre',

          test: /\.(js|vue)$/,

          loader: 'eslint-loader',

          exclude: /(node_modules)/

        });

      }

    }

  }

ok,这样就可以把mp3文件放到assets目录下了,你也可以在assets目录下新建media诸如此类的文件夹,然后把mp3文件塞进去。


千算万算没想到nuxt框架竟然没有帮忙配好mp3格式的编译,而只是配了mp4(video标签)的格式的loader。


好了,现在就可以像下图一样开心的写代码了


<audio id="audio" ref="audio" loop="loop" autoplay="autoplay">

    <source src="@/assets/music/exam.mp3" type="audio/mpeg">

    您的浏览器不支持 audio 元素。

</audio>

这样他就能识别出"@/assets/music/exam.mp3"是什么东西。


三、第二坑——IOS端在微信浏览器中不能自动播放音乐

这个也是弄了我很久,查阅了很多资料,但其实很简单,网上说IOS端为了防止恶意浪费流量所以禁止了自动播放音乐。但是微信浏览器中,可以通过监听WeixinJSBridgeReady和invoke的方法兼容IOS。


首先引入微信提供的js-sdk的js文件:(在nuxt.config.js中配置) (src: 'https://res.wx.qq.com/open/js/jweixin-1.1.0.js')




事不宜迟先上代码:


<script type="text/ecmascript-6">

export default {

  computed: {

    /* <audio ref="audio"></audio> */

    audio () {

      return this.$refs.audio;

    }

  },

  mounted () {

    this.autoPlayMusic();

  },

  methods: {

    autoPlayMusic () {

      // 监听微信h5自动播放bgm

      if (window.WeixinJSBridge) {

        window.WeixinJSBridge.invoke('getNetworkType', {}, () => {

          this.audio.play();

        }, false);

      } else {

        document.addEventListener('WeixinJSBridgeReady', () => {

          window.WeixinJSBridge.invoke('getNetworkType', {}, () => {

            this.audio.play();

          });

        }, false);

      }

    }

  }

};

</script>

这样之后,就可以打开微信h5应用后就可以听到音乐了。


注意了,网上有些说法是


document.addEventListener('DOMContentLoaded', function () {

    document.addEventListener("WeixinJSBridgeReady", function () {

          let audio = document.getElementById('audio')

          audio.play()

    }, false)

})

但是查了一下发现,DOMContentLoaded这个方法表示页面加载完成之后就会触发,就是说,对于单页应用来说,一旦首屏加载完成了,那么它就触发,之后就不会出发了。但是我这个播放音乐组件是要等到它进去某个页面才会开始加载的,所以一开始用了这个方法怎么样也不响。


噢对了,如果eslint报错WeixinJSBridge is not defined的话,那么在eslint.js中加上这段话:




这就没问题了,这个表示如果出现WeixinJSBridge这个时,不进行监测(代表它是全局变量)


四、总结

还以为移动端兼容性比浏览器更容易解决,没想到就这个bug搞了我很久,特别是ios竟然不能自动播放,幸好还是解决了,最后上一下我的音乐播放组件(其实很简单的慕课网很多教程,不过多年之后感觉慕课网那个一下子就能做出来)


<template>

  <div>

    <!-- ct-icon-music就是一个光碟的图标,用的是iconfont里面的,可以自己去找 -->

    <span @click="handleClick" :class="isStop ? '' : 'active'"></span>

    <audio id="audio" ref="audio" loop="loop" autoplay="autoplay">

      <source src="@/assets/music/exam.mp3" type="audio/mpeg">

      您的浏览器不支持 audio 元素。

    </audio>

  </div>

</template>

 

<script type="text/ecmascript-6">

export default {

  data () {

    return {

      isStop: false

    };

  },

  computed: {

    audio () {

      return this.$refs.audio;

    }

  },

  mounted () {

    this.autoPlayMusic();

  },

  methods: {

    /* 点击光碟图标就会播放/暂停音乐 */

    handleClick () {

      this.isStop = !this.isStop;

      if (this.isStop) {

        this.audio.pause();

        this.$emit('stop');

      } else {

        this.audio.play();

        this.$emit('start');

      }

    },

    autoPlayMusic () {

      // 监听微信h5自动播放bgm

      if (window.WeixinJSBridge) {

        window.WeixinJSBridge.invoke('getNetworkType', {}, () => {

          this.audio.play();

        }, false);

      } else {

        document.addEventListener('WeixinJSBridgeReady', () => {

          window.WeixinJSBridge.invoke('getNetworkType', {}, () => {

            this.audio.play();

          });

        }, false);

      }

    }

  }

};

</script>

 

<style scoped>

.audio-container {

  position: fixed;

  top: 45px;

  right: .5rem;

  text-align: right;

  .ct-icon-music {

    display: inline-block;

    &.active {

      animation: musicRotate 1.5s linear infinite;

    }

  }

}

@keyframes musicRotate {

  from { transform: rotateZ(0); }

  to { transform: rotateZ(360deg); }

}

</style>


  • 2018-11-17 22:44:53

    LeakCanary,30分钟从入门到精通

    在性能优化中,内存是一个不得不聊的话题;然而内存泄漏,显示已经成为内存优化的一个重量级的方向。当前流行的内存泄漏分析工具中,不得不提的就是LeakCanary框架;这是一个集成方便, 使用便捷,配置超级简单的框架,实现的功能却是极为强大的。

  • 2018-11-17 22:53:01

    gc for alloc freed

    在数组中选择图片然后显示,然后。。。logcat不断显示GC回收。最后程序黑屏。

  • 2018-11-17 23:25:38

    Android高效内存1:一张图片占用多少内存

    在做内存优化的时候,我们发现除了解决内存泄露问题,剩下的就只有想办法减少真实的内存占用。而在App中,大部分内存可能被我们图片占用了,所以减少图片的内存占用可以带来直接的效果。本文就简单介绍一张图片到底占用多少内存,我们先假设我们有一张图片时 600 * 800 的,图片占用空间大小假设是 100KB。另外本文知识点也是面试官喜欢问的一个点,看看自己的回答到什么级别了。

  • 2018-11-18 09:06:06

    Android子线程中更新UI的3种方法

    UI的更新必须在主线程中完成,所以不管上述那种方法,都是将更新UI的消息发送到了主线程的消息对象,让主线程做处理。

  • 2018-11-19 15:10:23

    nodemailer的使用,nodejs发送邮件

    前段时间有个很普通的项目需要发邮件的功能,而且是刚开始学nodejs,所以只是搜索了下用什么好的库能实现,就找到了nodemailer了。这篇文章主要是记录一下使用的过程和经验。

  • 2018-11-21 09:07:37

    Android为每个应用分配多少内存?

    熟悉Android内存分配机制的朋友都知道,Android为每个进程分配内存时,采用弹性的分配方式,即刚开始并不会给应用分配很多的内存,而是给每一个进程分配一个“够用”的内存大小。

  • 2018-11-22 21:13:28

    webview之独立进程

    app内存占用大,被系统回收的概率就高,当每次把app切到后台再回到app时,可能每次app都会重启,最常见的是activity或fragment被回收了,导致fragment使用activity的数据时,出现NullPointerException。内存占用大,app越不稳定。运行性能差。webview加载页面后会占用更多的内存,从而导致app内存占用大,最终导致出现以上问题。

  • 2018-11-22 21:14:34

    为什么要采用WebView独立进程

    App中大量Web页面的使用容易导致App内存占用巨大,存在内存泄露,崩溃率高等问题,WebView独立进程的使用是解决Android WebView相关问题的一个合理的方案。