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

2021年2月24日 335点热度 0人点赞 0条评论

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("致爱丽丝");//设置作品名字

图片

 

方法说明:

方法名称

参数

说明

setSrc

value:string类型,音频文件Url

设置要播放的音频文件

setPoster

value: string类型,海报图片Url

设置要要显示的海报图片(显示到播放按钮下)

setName

value: string类型,作品名

设置作品名

setSinger

value: string类型,歌手名

设置歌手名

stop

停止播放

seek

t:number类型,进度(秒)

跳转到第t秒播放

play

播放

pause

暂停播放

playbackRate

value:number类型,倍速

设置播放倍速,具体可选值请参考Uni-App文档里uni.createVideoContext的playbackRate方法。

需要特别注意:playbackRate方法不能在play/setSrc之前或者之后立即调用,否则只有很少几率会成功。如果需要在play/setSrc后调用,最好延时调用playbackRate。

 

播放器提供了三个文本区域供用户使用,可以在这三个文本区域中显示自定义内容,也可以响应它们的点击事件从而把它们当成按钮使用。也可以使用slot设置自定义UI。

图片


属性说明:

属性名

类型

默认值

说明

isButton1Visible

boolean

false

按钮1是否可见

button1Text

string

按钮1的文本

isButton2Visible

boolean

false

按钮2是否可见

button2Text

string

按钮2的文本

isButton3Visible

boolean

false

按钮3是否可见

button3Text

string

按钮3的文本

有三个事件“Button1Click、Button2Click、Button3Click”,当三个按钮点击的时候就会分别触发。

例子代码:

<yz-audio ref="player1"button1Text="按钮1" button2Text="按钮2" button3Text="按钮3"

isButton1Visible="true"isButton2Visible="true" isButton3Visible="true"@Button1Click="btn1Click">

</yz-audio>

 

如果这三个文本无法满足要求,也可以使用名字为extraCtrls的插槽来自定义这块的UI,如下:

<yz-audio ref="player1">

       <templatev-slot:extraCtrls>

              <uni-iconstype="camera"></uni-icons>

              <text>youzack.com</text>

       </template>

</yz-audio>

图片

 

事件说明:

名称

参数

说明

Button1Click

按钮1被点击

Button2Click

按钮2被点击

Button3Click

按钮3被点击

play

开始播放

pause

暂停

ended

结束播放

timeUpdate

{currentTime, duration},来自于video控件的timeUpdate事件参数的detail属性值。

播放进度变化时触发

error

错误对象

视频播放出错时触发   

 

注意事项:

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=>{

       leterr = res[0];

       letresp = res[1];

       if(err)

       {

              uni.showModal({                              

                     content:"调用失败"+err.errMsg

              });

              return;

       }

       uni.showModal({

              content:"调用成功"+resp

       });

});

 

示例代码2:

let err1,resp1;

[err1,resp1] = awaitzRetrier({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的参数还有其他属性。

参数:

  • retryTimes:整数类型。代表一次失败之后,最多自动重试retryTimes次,默认值是3。

  • retryWaitTime:整数类型,代表每次自动重试之前等待的毫秒数。默认值是200。

  • autoLoading:boolean类型,代表请求期间是否自动显示loading,默认值是true。

  • 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 getset !"></yz-text>

text属性中就是要显示的文字,长按文字后就会弹出分词对话框。

 

属性说明:

属性名

类型

默认值

说明

text

string

显示的文字

tips

string

“选择文本(可多选)后,可以点击【翻译】”

按钮底下的描述文字

button1Text

string

'翻译'

第一个按钮的文本

 

事件说明:

名称

参数

说明

split

{value,’’,words:[]}

如果不监听split事件或者split事件中设定e.words不是空,则按照英文进行分词。

split事件中对文字进行自定义分词,e.value是文字,e.words是分析后的字符串数组。

search

字符串

点击第一个按钮后触发,参数是用户选择的大爆炸文字。

 

示例代码:

<yz-text text="I love you, I've getset !"></yz-text>

<yz-text text="杨中科,一名快乐的程序员" @split="split"@search="search"

               tips="选中文字进行搜索"button1Text="搜索"></yz-text>

split:function(e)

{                   

       e.words=e.value.split("");

},

search:function(s)

{

       uni.showToast({

              title:s

       });

},

 

示例中的中文分词用的是简单的一元分词,你可以用更智能的其他分词算法。

 

我主要做后端开发,Uni-App等这些都是做这个小程序时候才现学的,所以如果有做的不好的地方,请指正,谢谢。

可以点击访问体验这些组件的使用:

体验youzack学英语小程序

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

这个人很懒,什么都没留下

文章评论