做 H5开发的一个需求:页面内有一个按钮点击可以播放语音,产品提供的素材是多段语音,并配有对应文字;
bug1: 切换到后台时,语音还在播放,
解决方法:增加 visibilitychange 监听事件,用 document.hidden 判断是否处于后台。
- mounted() {
- this.audioTemp = new Audio(AthenaData.audioList[0].voice);
-
-
- // 切到后台停止语音
- document.addEventListener('visibilitychange', () => {
- if (document.hidden) {
- this.musicDisabled = false; // 按钮状态
- this.audioTemp.pause();
- }
- });
- },
bug2: API can only be initiated by a user gesture
原因:部分安卓机要求调用 audio.play() 这个接口必须要用户手势触发,也就是必须是真实的用户操场类似 click之类的事件去触发才行,用js主动去触发dom的click的话也是无效的!
解决方案有二:1. 安卓端上有对应的 api 设置可以取消这个限制,但一定会有合规方面的风险(法务检测那边可能无法通过)2.将多段语音合成一段。
template:
- // 播放按钮
-
- v-image.normal="musicDisabled ? AthenaData.horn1 : AthenaData.horn2"
- class="horn1"
- @click="onBgmMusicClick"
- />
-
-
- // 滚动文字
- <div
- ref="box"
- class="tips-box"
- >
- <div
- ref="content"
- class="tips-content"
- :style="tranlateDo?{
- transition: `all ${tranlateTime}s linear`,
- transform: `translateX(-${tranlatex}px)`,
- }:{
- transform: 'translateX(0)'
- }"
- >
- {{ AthenaData.audioList[voiceIndex].label }}
- div>
- div>
data:
- data() {
- return {
- AthenaData, // 数据
- musicDisabled: false, // 播放按钮状态
- audioTemp: null, // 语音对象
- voiceIndex: 0, // 文字索引
- tranlateDo: false, // 文字滚动状态
- tranlatex: 0, // 文字滚动距离
-
- timeoutTicket: null, // 当前文字
- voiceTimeoutTicket: null, // 下一段文字
- };
- },
mounted:
-
- mounted() {
-
- // 设置语音播放列表
- this.audioTemp = new Audio(AthenaData.audioList[0].voice);
- this.audioTemp.onended = () => {
- this.musicDisabled = false;
- this.audioTemp.pause();
- this.audioTemp.load();
- this.tranlateDo = false;
- this.voiceIndex = 0;
- clearTimeout(this.voiceTimeoutTicket);
- };
-
- // 切到后台停止语音
- document.addEventListener('visibilitychange', () => {
- if (document.hidden) {
- this.musicDisabled = false;
- this.audioTemp.pause();
- this.tranlateDo = false;
- this.voiceIndex = 0;
- this.audioTemp.load();
- if (this.timeoutTicket) {
- clearTimeout(this.timeoutTicket);
- }
- clearTimeout(this.voiceTimeoutTicket);
- }
- });
- },
- computed: {
- // 读当前文字滚动的时间
- tranlateTime() {
- // 三目运算符容错
- return AthenaData.audioList[this.voiceIndex]
- ? AthenaData.audioList[this.voiceIndex].time - 1// 每段语音的首末有半秒背景音乐
- : 1;
- },
- },
methods:
- methods: {
- // 播放语音按钮回调
- onBgmMusicClick() {
- this.musicDisabled = !this.musicDisabled;
- if (this.musicDisabled && AthenaData.audioList.length) {
- this.audioTemp.play();
- this.setLabelPlay();
- }
- if (!this.musicDisabled) {
- this.audioTemp.pause();
- this.tranlateDo = false;
- this.voiceIndex = 0;
- this.audioTemp.load();
- if (this.timeoutTicket) {
- clearTimeout(this.timeoutTicket);
- }
- clearTimeout(this.voiceTimeoutTicket);
- }
- },
-
-
- //设置文字动画
- setLabelPlay() {
- // 语音有半秒前奏播放完后 再开始文字动画
- this.timeoutTicket = setTimeout(() => {
- this.tranlateDo = true;
- this.tranlatex = this.$refs.content.offsetWidth - this.$refs.box.offsetWidth;
- }, 500);
-
-
- clearTimeout(this.voiceTimeoutTicket);
- this.voiceTimeoutTicket = setTimeout(() => {
- // 目前只有三段文字,若索引为2说明到最后一段,置0停掉动画;否则处理下一段(+1后则显示下一段文字)
- this.voiceIndex = this.voiceIndex === 2 ? 0 : this.voiceIndex + 1;
- // 以下为控制下一段文字动画的逻辑
- if (this.voiceIndex !== 0) {
- // 停掉动画 从头滚动
- this.tranlateDo = false;
- this.tranlatex = 0;
- // 开始滚动
- this.setLabelPlay();
- } else {
- clearTimeout(this.voiceTimeoutTicket);
- }
- }, parseInt(AthenaData.audioList[this.voiceIndex].time, 10) * 1000); // 这个时间为当前动画持续的时间
- },
-
-
-
-
- }
最终效果如下,资源链接
屏幕录制2022-07-28 18.51.06
其实,不难发现,语音和文字的单独控制,只不过是卡住时间让效果看起来是同步。除此之外,还可以扩充暂停功能:播放语音中途点击按钮让语音和文字滚动暂停,再次点击时接着上述效果。原生实现方法只需增加一个变量记录点击时文字已滚动的距离,然后再次点击时进行判断,让动画接着滚动;如果引入其他动画库也许会有直接的API控制动画的暂停,实现起来更加简单。
Audio介绍
什么?你不知道audio是什么?它是h5新特性之一,audio可以理解为普通的dom对象,相关属性方法事件如下:
Audio对象的属性
Audio对象的方法
Audio对象的事件
事件和方法很像,只不过是可以传入回调函数增加更多逻辑
-
相关阅读:
MySQL 特殊字符
springMVC执行流程详解
静态HTML网页设计作品 DIV布局家乡介绍网页模板代码---(太原 10页带本地存储登录注册 js表单校验)
Metabase学习教程:仪表盘-4
基于PyQt5和PSoC6的多功能平衡车设计
【带你学c带你飞】1day 第2章 (练习2.2 求华氏温度 100°F 对应的摄氏温度
制作一个简单HTML个人网页网页——人物介绍梵高(HTML+CSS)
Unity中Shader需要了解的点与向量
云原生技术实践:Kubernetes集群的部署与运维
利用Jdk动态代理模拟MyBatis的Mapper功能
-
原文地址:https://blog.csdn.net/qq_37974755/article/details/126036916