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>


  • 2019-12-04 10:46:26

    nuxt.js项目中全局捕获异常并生成错误日志全过程

     需求:客户在使用过程中页面报错时,可以生成错误记录传回服务器,以便改进。   步骤:     一.全局捕获异常,     二.发送到服务端,     三.生成错误日志。   一.全局捕获异常 如图,vue提供了errorHandle这个方法来处理全局异常,更多详细内容参见官网。

  • 2019-12-04 10:47:59

    nuxt.js项目中全局捕获异常并生成错误日志全过程

     需求:客户在使用过程中页面报错时,可以生成错误记录传回服务器,以便改进。   步骤:     一.全局捕获异常,     二.发送到服务端,     三.生成错误日志。   一.全局捕获异常 如图,vue提供了errorHandle这个方法来处理全局异常,更多详细内容参见官网。

  • 2019-12-04 10:48:18

    vue 项目资源文件 static 和 assets 不说区别直接使用?

    assets中资源会webpack构建压缩到你代码中,而static文件直接引用。 static 中长存放类包、插件等第三方的文件,assets里放属资源文件比如自己资源图片、css文件、js文件。 引入资源的方式static文件夹可以使用~/static/方式引入, assets文件夹可以使用 ~@/assets 方式引入

  • 2019-12-05 17:01:36

    Vue 结合 Axios 接口超时统一处理

    当网路慢的时候。又或者公司服务器不在内地的时候,接口数据请求不回来超时报错的情况相信大家肯定遇到过的,这里我把我公司项目请求超时的处理方法分享下,希望看过后有帮助。

  • 2019-12-05 17:13:40

    JS模板工具lodash.template的简单用法

    lodash是从underscore分支的一个项目,之前我写了一篇JS模板工具underscore.template的简单用法,lodash跟underscore很相似,这也简单介绍一下lodash的template方法。 先把underscore的文章中用过的代码贴过来,把underscore的js文件换成lodash的js,其他一字不改,然后我们试试:

  • 2019-12-06 10:47:29

    date-fns日期工具的使用方法详解

    isToday() 判断传入日期是否为今天 isYesterday() 判断传入日期是否为昨天 isTomorrow() 判断传入日期是否为 format() 日期格式化 addDays() 获得当前日期之后的日期 addHours() 获得当前时间n小时之后的时间点 addMinutes() 获得当前时间n分钟之后的时间 addMonths() 获得当前月之后n个月的月份 subDays() 获得当前时间之前n天的时间 subHours() 获得当前时间之前n小时的时间 subMinutes() 获得当前时间之前n分钟的时间 subMonths() 获得当前时间之前n个月的时间 differenceInYears() 获得两个时间相差的年份 differenceInWeeks() 获得两个时间相差的周数 differenceInDays() 获得两个时间相差的天数 differenceInHours() 获得两个时间相差的小时数 differenceInMinutes() 获得两个时间相差的分钟数

  • 2019-12-06 10:49:39

    npm 查看源 换源

    npm,cnpm,查看源,切换源,npm config set registry https://registry.npmjs.org