239 lines
4.6 KiB
Vue
239 lines
4.6 KiB
Vue
<template>
|
|
<section class="ai-audio">
|
|
<div class="controller" :class="skinClassName">
|
|
<el-row :gutter="10" type="flex">
|
|
<el-col>
|
|
<i class="play-icon" :class="playIcon" @click="play"></i>
|
|
</el-col>
|
|
<el-col class="play-progress">
|
|
<el-slider
|
|
:format-tooltip="getDateFormat"
|
|
v-model="currentTime"
|
|
:max="totalDuration"
|
|
@change="audio.currentTime = currentTime">
|
|
</el-slider>
|
|
<span class="total" v-if="skin === 'flat'">{{ getDateFormat(currentTime) }}</span>
|
|
<span class="total" v-else>{{ [getDateFormat(currentTime), getDateFormat(totalDuration)].join('/') }}</span>
|
|
</el-col>
|
|
</el-row>
|
|
<audio
|
|
ref="audio"
|
|
style="display: none;"
|
|
:src="src"
|
|
preload="metadata"
|
|
@pause="playState = false"
|
|
@playing="playing"
|
|
@loadedmetadata="loadedmetadata"
|
|
@timeupdate="timeupdate"
|
|
></audio>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<script>
|
|
import moment from 'dayjs'
|
|
|
|
export default {
|
|
name: 'AiAudio',
|
|
props: {
|
|
/**
|
|
* 播放资源url
|
|
*/
|
|
src: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
/**
|
|
* 同时只允许一个播放
|
|
*/
|
|
singlePlay: {type: Boolean, default: false},
|
|
/**
|
|
* 播放器风格
|
|
* default 旧版样式,flat 新版样式
|
|
* @values default,flat
|
|
*/
|
|
skin: {
|
|
type: String,
|
|
default: 'default'
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
audio: null,
|
|
playState: false,
|
|
currentTime: 0,
|
|
totalTime: 0
|
|
}
|
|
},
|
|
computed: {
|
|
playIcon() {
|
|
if (this.skin === 'flat') {
|
|
return this.playState ? 'iconfont iconMediaPlayer_Stop' : 'iconfont iconMediaPlayer_Play'
|
|
}
|
|
|
|
return this.playState ? 'el-icon-video-pause' : 'el-icon-video-play'
|
|
},
|
|
|
|
totalDuration() {
|
|
return Math.round(this.totalTime)
|
|
},
|
|
|
|
skinClassName() {
|
|
return this.skin === 'default' ? '' : this.skin
|
|
}
|
|
},
|
|
|
|
mounted() {
|
|
this.audio = this.$refs.audio
|
|
},
|
|
|
|
methods: {
|
|
play() {
|
|
if (this.audio) {
|
|
if (this.audio.paused) {
|
|
if (this.singlePlay) this.stopAllAudio()
|
|
this.audio.play()
|
|
} else {
|
|
this.audio.pause()
|
|
}
|
|
}
|
|
},
|
|
|
|
stopAllAudio() {
|
|
let audios = document.getElementsByTagName('audio')
|
|
for (let i = 0; i < audios.length; i++) {
|
|
if (audios[i]) audios[i].pause()
|
|
}
|
|
},
|
|
|
|
playing() {
|
|
this.playState = true
|
|
},
|
|
|
|
loadedmetadata() {
|
|
this.totalTime = this.$refs.audio.duration || 0
|
|
},
|
|
|
|
getDateFormat(val) {
|
|
const time = moment.duration(val, 'seconds')
|
|
return [
|
|
this.prefixNum(time.minutes(), 2),
|
|
this.prefixNum(time.seconds(), 2),
|
|
].join(':')
|
|
},
|
|
|
|
prefixNum(val, num) {
|
|
return (Array(num).join('0') + val).slice(-num)
|
|
},
|
|
|
|
timeupdate() {
|
|
this.currentTime = parseInt(this.audio.currentTime)
|
|
}
|
|
},
|
|
|
|
destroyed() {
|
|
this.audio.pause()
|
|
}
|
|
}
|
|
</script>
|
|
<style lang="scss" scoped>
|
|
.ai-audio {
|
|
display: flex;
|
|
flex: 1;
|
|
|
|
.controller {
|
|
width: 205px;
|
|
height: 40px;
|
|
padding: 0 5px;
|
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
border-radius: 99px;
|
|
|
|
.el-col {
|
|
width: auto;
|
|
}
|
|
|
|
.play-icon {
|
|
color: #4c84ff;
|
|
cursor: pointer;
|
|
line-height: 40px;
|
|
font-size: 32px;
|
|
transition: color 0.3s;
|
|
|
|
&:hover {
|
|
color: #b3d8ff;
|
|
}
|
|
}
|
|
|
|
.play-progress {
|
|
display: flex;
|
|
flex: 1;
|
|
|
|
.el-slider {
|
|
width: 60px;
|
|
}
|
|
|
|
.total {
|
|
margin-left: 15px;
|
|
font-size: 12px;
|
|
line-height: 40px;
|
|
}
|
|
}
|
|
}
|
|
|
|
.flat {
|
|
height: 32px;
|
|
background: rgba(239, 246, 255, 1);
|
|
border: 1px solid rgba(132, 181, 255, 1);
|
|
border-radius: 5px;
|
|
box-shadow: none;
|
|
|
|
.play-icon {
|
|
position: relative;
|
|
padding-left: 3px;
|
|
color: #4c84ff;
|
|
cursor: pointer;
|
|
line-height: 32px;
|
|
font-size: 20px;
|
|
transition: color 0.3s;
|
|
|
|
&:hover {
|
|
color: #b3d8ff;
|
|
}
|
|
}
|
|
|
|
:deep(.el-slider__button ){
|
|
width: 8px;
|
|
height: 8px;
|
|
background: #1365DD;
|
|
}
|
|
|
|
:deep(.el-slider__bar ){
|
|
height: 2px;
|
|
}
|
|
|
|
:deep(.el-slider__button-wrapper ){
|
|
height: 32px;
|
|
}
|
|
|
|
:deep(.el-slider__runway ){
|
|
height: 2px;
|
|
margin: 15px 0;
|
|
}
|
|
|
|
.play-progress {
|
|
display: flex;
|
|
|
|
.el-slider {
|
|
width: 84px;
|
|
}
|
|
|
|
.total {
|
|
margin-left: 8px;
|
|
font-size: 12px;
|
|
line-height: 32px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|