微信浏览器可滚动消息轮播带提示音的解决方案

423 阅读4分钟

场景

  • 最近接到一个产品需求,需要在一个分享端外的 H5 页面中增加一个弹窗,弹窗的内容是根据接口获取的一些消息,这些消息需要一条一条的轮播出来,并且每一条消息出来是都要有一个消息提示音。

前提

  1. 技术:Vue2.0vant2.12.27
  2. 环境:微信浏览器;
  3. 场景:定时自动弹窗、轮播消息并伴有声音、消息区域高度固定且超出滚动。
  4. 开发测试机型:Android 华为的 HarmonyOS 系统。

问题

  1. 消息超出设置滚动在 iOS 上无法滚动;
  2. 消息轮播时,声音播放不生效。
  • 记住这里的前提,对后面很重要。

问题一

  • 由于是一个弹窗并且需要背景色透明度,自然而然的想到了使用 vant 中的 overlay 组件,于是就正常的使用这个组件作为弹窗的包裹层(为了偷懒,当然有现成的组件不用是傻子,不然为啥要引入组件库呢,对吧?)。 image.png
  • 在开发过程中,由于没有真实的微信浏览器环境,所以使用的正常的浏览器环境,并且调试使用的是 Android 华为的 HarmonyOS 系统。这两个原因都导致了这个问题。

基本结构

<overlay class="dialog-overlay">
    <div class="content">
        <div class="content-header" />
        <div class="content-center" />
        <div class="content-footer" />
    </div>
</overlay>
  • content-center 中就是显示消息的区域,对外层的 dialog-overlaycontent 都设置了 display: flex; 并对 content-center 设置了下列属性:
flex: 1;
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
-ms-overflow-style: none;
overflow: -moz-scrollbars-none;
...
  • 在本地开发完成后发现是可以用的,于是就发布部署到 dev 环境,通过分享到自己的微信测试(iOS),使用测试的 Android 测试,发现都无法滚动。

查找原因

  1. 是否是上层有什么元素遮挡,导致手指按下未触到可滚动的元素区域,使用 vconsole 打开 debug 模式,审查元素,元素正常无遮挡。
  2. 是否是属性未生效,检查属性问题;亦或者是 flex 属性导致无法滚动;都尝试过发现还是无法滚动,且对比其他同样在微信浏览器环境下设置了同样的属性是可以生效(滚动)的。
  3. 在对比其他微信浏览器环境下可滚动的元素发现,唯一有一点不同的就是最外层的元素不一样,于是去掉 overlay 组件,改用 div,重新发布部署后 iOSAndroid 都可用。
  • 查找相关问题,发现很多人都遇到过,所以只要定位到问题,你遇到的基本上前面都有人遇到了,如何解决就变得简单了。关键是学会如何定位排查问题。

问题二

  • 在做之前,我写了一个 demo 在手机浏览器环境试过,发现完全没有问题,觉得就这?这么简单的吗? image.png
  • 万万没想到的是,就这,我调试部署了好几次最后才将其解决。

就这方案一

  • 方案一也就是 demo 中使用的方式,代码异常的简洁,如下:
const mp3 = new Audio('xxx.mp3');
setInterval(() => {
    mp3.load();
    mp3.play();
}, 1000)
  • 是不是非常的简单,在我华为 HarmonyOS 系统的测试机上可是一点问题都没有,非常的流畅,于是自行的提到 dev 环境,并分享微信中打开体验。iOS 打开没有声音???一定是我没有开手机音量,开启所有音量打开还是没有声音。我:......。于是拿另外的 Android 测试机试试,发现依旧没有声音。

打击方案二

  • 由于方案一的失败,依然觉得这个应该也不是很能,一定是我打开的方式不对,既然直接 new 不行,那我把它放到 HTML 中总行了吧。于是乎改成了下面的代码:
// html
<audio ref="audioRef">
    <source src="xxx.mp3" type="audio/mp3" />
</audio>

js
const audioRef = this.$refs.audioRef;
setInterval(() => {
    audioRef.load();
    audioRef.play();
}, 1000)
  • 是不是依然很简单,于是又一次发不到 dev 测试,测试结果发现 iOS 依旧不行, Android 偶尔有声音,但是消息出现和声音对不上,有时候也没有声音。

查阅方案三

  • 前两个方案都不行,那只能搜索看一下有没有啥解决方案了。查阅发现自 2020年4月8日起,Android 微信浏览器环境的音频自动播放做了调整,Android微信内网页音频自动播放能力调整
  • 于是乎,只要我 Android 上可以,那 iOS 基本上应该是没问题了,通过之前的积累知道微信浏览器有这样一个事件:
document.addEventListener(
    'WeixinJSBridgeReady',
    () => {
        console.log('WeixinJSBridgeReady');
    },
    false
);
  • 于是我尝试基本页面 mounted 中,监听 WeixinJSBridgeReady,在微信环境准备就绪后去初始化我们想播放的音频,如下:
document.addEventListener(
    'WeixinJSBridgeReady',
    () => {
        console.log('WeixinJSBridgeReady');
        const audio = document.createElement('audio');
        audio.setAttribute('id', 'msgAudio');
        audio.setAttribute('src', 'https://cd-user-upload.hongsong.club/txd/living-h5/hint-sound.mp3');
        document.body.appendChild(audio);
    },
    false
);
  • 在子组件弹窗中使用
const mp3 = document.getElementById('msgAudio');
this.timer = setInterval(() => {
    if (i < len) {
        if (mp3) {
            mp3.load?.();
            mp3.play?.();
        }
        this.renderList.push(this.totalList[i]);
        i++;
        this.pushToView();
    } else {
        this.cantScroll = false;
        clearInterval(this.timer);
    }
}, 1000);
  • 这里顺便安利一个方法 scrollIntoView,可以将制定元素滚动到可视区域。
pushToView() {
    this.$nextTick(() => {
        const itemList = document.querySelectorAll('.message-item');
        itemList[itemList.length - 1]?.scrollIntoView(false);
    });
},
  • 发布部署到 dev 直接用 Android 测试,发现声音随消息一起播放弹出,避免偶然,多次关闭,打开都没有问题;切换 iOS 果然也是正常的。

image.png

总结

  • 在开发过程中出现问题是很正常的,尤其是有些环境不好测试,开发时没有对应的环境调试。出现问题后可以通过自己的一些猜测去尝试解决;如果无法解决可以查阅网上的资料,描述自己的问题。
  • 如果是工作没多久的没有啥经验的话,先尝试自己解决(一定要先自己尝试),多次尝试实在无法解决可以找带自己的前辈或leader请教。

往期精彩

「点赞、收藏和评论」

❤️关注+点赞收藏+评论+分享❤️,手留余香,谢谢🙏大家。