1 audio简介
- audio是html5新标签
- audio用来定义声音,比如音乐或其他音频流
2 此篇文章背景
❝业务中经常遇到使用audio场景,比如音乐播放,比如即时聊天语音,最近在实现智能问答机器人,其中涉及到音频这块内容。 大部分情况下,设计稿不会使用浏览器默认的audio样式,而audio样式又不能直接通过css样式改变成我们想要的效果
❞
3 看看一般浏览器默认样式和设计稿的差别之处
浏览器默认(谷歌)
一般设计稿
4 开始需求分析
- 播放器有播放暂停功能
- 开始时间和结束时间
- 播放进度(随着播放时间变化)
- 音量调节 (大部分用到音频的场景也就这些需求)
5实现UI界面
<div className="audioComponent">
<audio
id={`myAudio${id}`}
src={src}
onCanPlay={() => this.changeAudio('allTime')}
onTimeUpdate={(e) => this.changeAudio('getCurrentTime')}
>
您的浏览器不支持 audio 标签。
</audio>
{
isPlay?
<svg onClick={() => this.changeAudio('pause')} t="1588991144735"
className="icon" viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="3155" width="32" height="32">
<path d="M304 176h80v672h-80z m408 0h-64c-4.4 0-8 3.6-8 8v656c0
4.4 3.6 8 8 8h64c4.4 0 8-3.6 8-8V184c0-4.4-3.6-8-8-8z" p-id="3156"
fill="#ffffff">
</path>
</svg>
:
<svg onClick={() => this.changeAudio('play')} t="1588991060671"
className="icon" viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="2228" width="32" height="32">
<path d="M275.2 185.6v656L812.8 512z" fill="#ffffff" p-id="2229">
</path>
</svg>
}
<span className="current">
{this.millisecondToDate(currentTime)+' / '+this.millisecondToDate(allTime)}
</span>
<input
type="range"
className="time"
ref={this.playInput}
step="0.01"
max={allTime}
value={currentTime}
onChange={(value) => this.changeAudio('changeCurrentTime',value)}
/>
<div className="volume-box">
{
isMuted ? <svg onClick={() => this.changeAudio('muted')} t="1589002703280"
className="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3429" width="32" height="32"><path d="M469.726 139.266v0l-217.47 163.104h-135.985c-37.804 0-67.889 30.141-67.889 67.327v273.082c0 36.683 30.397 67.327 67.889 67.327h135.985l217.47 163.104c30.237 22.675 54.353 10.267 54.353-27.359v-679.232c0-37.152-24.338-49.873-54.353-27.359z" p-id="3430" fill="#ffffff"></path><path d="M887.187 538.378l69.126-69.126c22.907-22.907 22.907-60.044 0-82.958v0c-22.907-22.907-60.044-22.907-82.958 0l-69.126 69.126-69.126-69.126c-22.907-22.907-60.044-22.907-82.958 0s-22.907 60.044 0 82.958l69.126 69.126-69.126 69.126c-22.907 22.907-22.907 60.044 0 82.958v0c22.907 22.907 60.044 22.907 82.958 0l69.126-69.126 69.126 69.126c22.907 22.907 60.044 22.907 82.958 0v0c22.907-22.907 22.907-60.044 0-82.958l-69.126-69.126z" p-id="3431" fill="#ffffff"></path></svg> :
<svg onClick={this.showVioce.bind(this)} t="1589001111572"
className="icon" viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="2482" width="32" height="32"><path d="M689.085 335.699c-18.785-18.785-49.239-18.785-68.023 0s-18.785 49.239 0 68.023c56.355 56.355 56.355 147.717 0 204.069-18.785 18.785-18.785 49.239 0 68.023 18.785 18.785 49.239 18.785 68.023 0 93.92-93.92 93.92-246.199 0-340.125z" p-id="2483" fill="#ffffff"></path><path d="M463.835 159.435v0l-205.238 153.931h-128.336c-35.674 0-64.067 28.451-64.067 63.543v257.721c0 34.619 28.684 63.543 64.067 63.543h128.336l205.238 153.931c28.537 21.398 51.299 9.69 51.299-25.82v-641.027c0-35.062-22.971-47.065-51.299-25.82z" p-id="2484" fill="#ffffff"></path><path d="M825.132 199.656c-18.785-18.785-49.239-18.785-68.023 0s-18.785 49.239 0 68.023c131.492 131.492 131.492 344.682 0 476.174-18.785 18.785-18.785 49.239 0 68.023 18.785 18.785 49.239 18.785 68.023 0v-0.001c169.060-169.060 169.060-443.158 0-612.221z" p-id="2485" fill="#ffffff"></path></svg>
}
<div className="pannel">
<input
type="range"
style={{backgroundSize: '100%',display: showVioce ? 'inline-block': 'none'}}
ref={this.vioceInput}
className="volume"
onChange={(value) => this.changeAudio('changeVolume',value)}
value={isMuted ? 0 : volume}
/>
</div>
</div>
</div>
svg是引入的小图标 css部分
.audioComponent {
display: flex;
align-items: center;
background-color: $mainColor;
padding: 5px;
svg {
width: 24px;
height: 24px;
}
border-radius: 24px;
input[type=range]{
outline: none;
margin-left: 10px;
-webkit-appearance: none;/*清除系统默认样式*/
// width:56% !important;
background: -webkit-linear-gradient(#61bd12, #61bd12) no-repeat, #ddd;
background-size: 0% 100%;/*设置左右宽度比例*/
height: 3px;/*横条的高度*/
}
/*拖动块的样式*/
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;/*清除系统默认样式*/
height:16px;/*拖动块高度*/
width: 16px;/*拖动块宽度*/
background: #fff;/*拖动块背景*/
border-radius: 50%; /*外观设置为圆形*/
border: solid 1px #ddd; /*设置边框*/
}
.volume-box {
display: flex;
position: relative;
margin-left: 10px;
}
.pannel {
background: $areaBgColor;
position: absolute;
top: -26px;
left: -38px;
display: flex;
align-items: center;
height: 20px;
}
.volume {
width: 80px;
margin-left: 0;
}
}
audio标签有几个属性值得关注
- id:多数情况需要循环展示audio,每个audio要有自己的id
- src: 音频路径或资源路径
- onCanPlay: 当资源可以正常播放的时候
- onTimeUpdate: 当时间更新
6 js实现
在state中定义一下变量
isPlay: false, // 是否播放 默认不播放
isMuted: false, // 是否静音
volume: 100, // 默认音量值
allTime: 0, // 音频总时长
currentTime: 0, // 当前播放时间
showVioce: false // 是否展示静音图标
用两个input表示播放进度条和音量进度条,在js中使用ref进行标识控制
this.playInput = React.createRef();
this.vioceInput = React.createRef();
音频时间计算
millisecondToDate(time) {
const second = Math.floor(time % 60)
let minite = Math.floor(time / 60)
return `${minite}:${second >=10? second: `0${second}`}`
}
改变音频
changeAudio(type,value) {
const { id,src } = this.props;
const { allTime } = this.state;
const audio = document.getElementById(`myAudio${id}`)
switch(type) {
case 'allTime':
this.setState({
allTime: audio.duration
})
break
case 'play':
audio.play()
this.setState({
isPlay: true
})
break
case 'pause':
audio.pause()
this.setState({
isPlay: false
})
break
case 'muted':
this.setState({
isMuted: !audio.muted
})
audio.muted = !audio.muted
break
case 'changeCurrentTime':
let str = (value.target.value)/allTime * 100 + "% 100%";
this.playInput.current.style.backgroundSize = str;
this.setState({
currentTime: value.target.value
})
audio.currentTime = value.target.value
if(value.target.value == audio.duration) {
this.setState({
isPlay: false
})
}
break
case 'getCurrentTime':
let str1 = (audio.currentTime)/allTime * 100 + "% 100%";
this.playInput.current.style.backgroundSize = str1;
this.vioceInput.current.style.backgroundSize = this.state.volume + '% 100%';
this.setState({
currentTime: audio.currentTime
})
if(audio.currentTime == audio.duration) {
this.setState({
isPlay: false
})
}
break
case 'changeVolume':
audio.volume = value.target.value / 100;
let str3 = value.target.value + '% 100%';
this.vioceInput.current.style.backgroundSize = str3;
console.log(value.target.value)
this.setState({
volume: value.target.value,
isMuted: !parseFloat(value.target.value)
},() => {
console.log(this.state.isMuted)
})
break
}
}
是否展示静音图标(在音量为0时切换成静音图标)
showVioce () {
let { showVioce } = this.state;
if(showVioce) {
this.setState({
showVioce: false
})
} else {
this.setState({
showVioce: true
})
}
}
根据不同状态通过changeAudio函数对音频播放进行控制
最终奉上动态图片效果
本文使用 mdnice 排版