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>


  • 2020-03-13 19:58:19

    推荐Android两种屏幕适配方案

    在Android开发中,由于Android碎片化严重,屏幕分辨率千奇百怪,而想要在各种分辨率的设备上显示基本一致的效果,适配成本越来越高。虽然Android官方提供了dp单位来适配,但其在各种奇怪分辨率下表现却不尽如人意,因此下面探索一种简单且低侵入的适配方式。本文将推荐两种屏幕适配方案,大家可以根据实际情况使用。

  • 2020-03-14 16:35:00

    nuxt.js部署全过程(ubuntu+nginx+node+pm2)

    系统的话本篇是Ubuntu 16.04.6 ,centos也行,大同小异都是Linux。不过如果你是初学者,最好和我使用一样的,因为因为发行版本不同而导致的差异可能导致运行某些东西失败,找问题要找好久。windows server不推荐了,企业用的多,小服务器跑windows server比较费劲。

  • 2020-03-14 23:15:25

    icomoon使用详细介绍

    此篇博文讲述如何利用icomoon导入图标,从而把自己想要的都通过icomoon方式进行,大家都知道,网站以及移动端,用图标还是尽量选择这种。因为直接用image有些图标会失真,从而也是前端开发之中,需求去掌握的一项,很简单的就几个步骤。

  • 2020-03-14 23:39:59

    vuetify和@nuxt/vuetify icon 之我见

    vuetify中v-icon,貌似默认支持 Material Design Icons, Material Icons, Font Awesome 4 and Font Awesome 5, 我自己单独引入了vuetify 用哪一个图标都没有问题。但是用了@nuxt/vuetify只能用mdi-home这样的。不知道因为啥。肯定是封装后,封装成一个了。 但是我修改vuetify的设置,哪一个图标也都能用。哎,不过多研究了。

  • 2020-03-16 15:57:53

    nuxtjs中单独引入Message组件的问题

    // 引入elementUIimport { Message } from 'element-ui';//由于Message组件并没有install 方法供Vue来操作的,是直接返回的,因此按照官方文档单独引入的方法是//会报错的,需要给 Message 添加 install 方法Message.install = function (Vue, options) {Vue.prototype.$message = Message}Vue.use(Message )//消息提示

  • 2020-03-16 16:03:20

    css的var()函数

     随着sass,less预编译的流行,css也随即推出了变量定义var函数。var()函数,就如同sass和less等预编译软件一样,可以定义变量并且进行对应的使用。