开源三个UniApp组件:倍速播放的音频播放器、网络重试、分词大爆炸

youzack是我开发的一个能进行英语听力逐句精听训练以及背单词的网站,为了方便移动端的使用,我使用Uni-App来进行youzack移动端的开发,因为Uni-App不仅可以用来开发微信小程序,也可以打包为App。
在开发的过程中,我封装了三个大家可能用到的Uni-App组件,他们分别是:支持音频倍速播放以及自定义UI的音频播放器yz-audio、支持自动网络重试请求的zackRetrier、支持类似于锤子手机的“大爆炸分词”的yz-text。
源码地址: https://github.com/yangzhongke/uniapp-youzack-components
下面分别来介绍他们的用法以及实现原理:
一、倍速音频播放器yz-audio
youzack中需要播放听力音频,Uni-App有<audio>组件,但是有如下缺点:不被推荐使用了;不支持变速播放功能;界面不能自定义。因此我开发了yz-audio这个组件。
插件地址:https://ext.dcloud.net.cn/plugin?id=4246

yz-audio特点:支持音频的变速播放;界面中内置了三个可以自定义内容的文本区域,可以响应点击事件,也可以使用slot自定义UI;
基本使用方式:
<yz-audio ref="player1">
</yz-audio>
在代码中播放以及设置名字、海报图片等:
var player1 = this.$refs.player1; player1.setSrc(
"https://vkceyugu.cdn.bspapp.com/VKCEYUGU-hello-uniapp/2cc220e0-c27a-11ea-9dfb-6da8e309e0d8.mp3");
player1.setPoster("https://vkceyugu.cdn.bspapp.com/VKCEYUGU-uni-app-doc/7fbf26a0-4f4a-11eb-b680-7980c8a877b8.png");//海报图片
player1.setSinger("贝多芬");//设置歌手
player1.setName("致爱丽丝");//设置作品名字

更多用法详见 https://ext.dcloud.net.cn/plugin?id=4246
注意事项:
1、 只有video组件支持倍速播放,所以这个组件是采用的video来播放音频,因此支持的音频文件格式取决于video组件的支持情况;
2、 由于VideoContext的内部实现的未知原因,不能在play方法之前或者之后立即调用playbackRate来修改倍速,否则很可能不会生效。最好由用户触发的动作来调用playbackRate,如果必须在play方法前后调用,建议通过setTimeout设置一个延时来执行playbackRate。
比如如下是不行的:
var player1 = this.$refs.player1;
player1.setSrc("https://www.test.com/test.mp3");
player1.playbackRate(0.5);
可以如下修改:
var player1 = this.$refs.player1;
player1.setSrc("https://www.test.com/test.mp3");
setTimeout(function(){player1.playbackRate(0.5);},500);
3、 由于组件是使用video来播放音频,因此具有video的所有缺点,比如不能实现后台播放。我曾经想换用getBackgroundAudioManager()来替换video,但是发现BackgroundAudioManager响应速度很慢,无法实现精细、及时的进度控制。
4、 如果需要音频的锁屏播放,可以在需要后台播放的时候(需要用户操作触发),暂停yz-audio的播放,然后再调用getBackgroundAudioManager实现后台播放。
5、 如果仔细观察播放器,你可能会发现右上角有一个小黑点,那个其实就是一个尺寸非常小的video组件。但是这个video组件不能完全隐藏,否则在ios下将会无法播放。
6、 由于播放器属于个性化需求非常强的组件,众口难调,因此这个组件很难完全满足所有人的要求,因此这个组件我只是开放源代码,各位可以根据自己的需要修改,我将不会进行后续维护、新需求增加等。
二、网络请求重试zackRetrier
在网络信号不强等情况下,网络请求可能会失败,因此我开发了一个能自动对失败的请求进行重试的组件zackRetrier,如果N次重试都失败了,还会弹出对话框问用户“是否再次重试”。在请求处理期间会自动显示loading提示。
插件地址:https://ext.dcloud.net.cn/plugin?id=4247

用法:
首先引入组件import {zRetrier} from "@/js_sdk/yz-zackRetrier/zackRetrier/index.js";
调用发送网络请求:zRetrier({url:"https://api.youzack.com/test"}),zRetrier函数返回的是Promise对象,所以既可以用await的方式获取调用结果,也可以使用then()方式。返回值是一个长度为2的数组,数组的第一个元素是错误对象,如果调用成功了,则第一个元素是null,数组的第二个元素是服务器端返回的响应。
示例代码1
zRetrier({url:"https://api.youzack.com/test",manualRetryContent:"登录失败,是否重试"})
.then(res=>{
let err = res[0];
let resp = res[1];
if(err)
{
uni.showModal({
content:"调用失败"+err.errMsg
});
return;
}
uni.showModal({
content:"调用成功"+resp
});
});
示例代码2:
let err1,resp1;
[err1,resp1] = await zRetrier({url:"https://api.youzack.com/test",manualRetryContent:"登录失败,是否重试"});
if(err1)
{
uni.showModal({
content:"调用失败"+err1.errMsg
});
return;
}
uni.showModal({
content:"调用成功"+resp1
});
zRetrier函数只有一个参数,这个参数会完整的传递给内部封装的uni.request方法,所以如果想设定method、headers等,用法和uni.request一样。除此之外,zRetrier的参数还有其他属性。
参数:
1) retryTimes:整数类型。代表一次失败之后,最多自动重试retryTimes次,默认值是3。
2) retryWaitTime:整数类型,代表每次自动重试之前等待的毫秒数。默认值是200。
3) autoLoading:boolean类型,代表请求期间是否自动显示loading,默认值是true。
4) manualRetryContent:string类型。如果设置了manualRetryContent的值,则在retryTimes次自动重试都失败后,会显示重试对话框,然后对话框中显示manualRetryContent的内容。对话框中有【取消】、【重试】两个按钮,如果用户点击了【重试】按钮之后,会再自动最大重试retryTimes次。
感谢C#中发明了await、async关键字极大的简化了异步编程,并且让JavaScript从C#中把这两个关键字借鉴了过来,最终能让我实现这个组件起来太简单了。
注意事项:由于这个组件可能多次重试后端接口,所有后端的接口需要是幂等的,也就是调用一次和调用N次的效果应该是一样的。
三、允许自定义选择菜单的“分词大爆炸”yz-text
为了方便用户直接查询例句中某个单词或者词组的中文翻译,youzack小程序中需要允许用户对于界面中的英文选中进行查询。微信小程序中,可以对于<text>设定user-select=”true”来允许用户自由选择其中的文字,在Android手机中,选中文字会弹出一个只带【复制】一个菜单项的菜单,在苹果手机中,选中文字会弹出一个带【查询】等菜单项的菜单。但是这个菜单中是无法自定义菜单项的。
我想监听剪切板中内容的变化,来实现“用户复制单词后自动查询单词”的功能。但是微信小程序中没有提供监听剪切板内容变化的API,所以只能用定时器监听剪切板中的内容。发布后,有用户反映,在小米的某些手机上,手机系统会频繁的提示“应用正在读取剪切板中的内容”,非常影响使用。这个可以理解,为了保护用户隐私,避免很多应用通过监听剪切板来偷窥用户的内容,因此新版的IOS和Android中都会做出类似的提示。
因此我换了另外一种思路,我借鉴锤子手机中“分词大爆炸”的效果,在用户长按一段文字后,弹出对话框,在对话框中对于文字进行分词,然后允许用户选中一个或者多个单词,然后进行查询。这样不仅规避了问题,而且用户的使用体验更好,真是无心插柳柳成荫呀。

插件地址:https://ext.dcloud.net.cn/plugin?id=4249
组件用法:
<yz-text text="I love you, I've get set !"></yz-text>
text属性中就是要显示的文字,长按文字后就会弹出分词对话框。
更多用法详见 https://ext.dcloud.net.cn/plugin?id=4249
我主要做后端开发,Uni-App等这些都是做这个小程序时候才现学的,所以如果有做的不好的地方,请指正,谢谢。