有你在真好 的个人博客
开源三个UniApp组件,罗永浩,锤子手机“大爆炸”我实现了
阅读:2209 添加日期:2021/3/27 23:16:10 原文链接:https://www.toutiao.com/item/6932761965509149191/

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


开源三个UniApp组件,罗永浩,锤子手机“大爆炸”我实现了

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。


开源三个UniApp组件,罗永浩,锤子手机“大爆炸”我实现了

属性说明:

属性名

类型

默认值

说明

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">

<template v-slot:extraCtrls>

<uni-icons type="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


开源三个UniApp组件,罗永浩,锤子手机“大爆炸”我实现了

用法:

首先引入组件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


开源三个UniApp组件,罗永浩,锤子手机“大爆炸”我实现了

组件用法:

<yz-text text="I love you, I've get set !"></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 get set !"></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

});

},


开源三个UniApp组件,罗永浩,锤子手机“大爆炸”我实现了

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


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

ICP备案号:苏ICP备14035786号-1 苏公网安备 32050502001014号