console
Vue.component('player', {
template: `
<div style="position: relative;">
<div class="audio-wrapper">
<div class="player-btn">
<img src="http://aikangclouditer-new.oss-cn-qingdao.aliyuncs.com/static_image/loading.gif" class="loading" v-if="playState==3" @click="pause">
<img src="http://aikangclouditer-new.oss-cn-qingdao.aliyuncs.com/static_image/audio.gif" class="voice" v-if="playState==1" @click="pause">
<img src="http://aikangclouditer-new.oss-cn-qingdao.aliyuncs.com/static_image/audio.png" class="voice" v-else @click="play">
</div>
<div class="right">
<div v-if="title" class="title">{{title}}</div>
<div class="audio-player">
<div class="slide-wrapper">
<div class="line" ref="line" :style="{width:percent*100+'%'}">
<i class="dot" ref="dot"></i>
</div>
</div>
<div class="time-wrapper">
<div class="cur-time" v-text="showDuraTime(curTime)"></div>
<div class="duration" v-text="showDuraTime(duration)"></div>
</div>
</div>
</div>
<audio id="audio" v-show="false" controls ref="player" preload class="player" :src="audioSrc"
@waiting="playState=3"
@timeupdate="updateProgess" @playing="playState=1;" @ended="playState=5;isEnd=true;"></audio>
</div>
</div>
`,
props: {
audioSrc: {
type: String,
default: ''
},
duration: {
type: Number,
default: 0
},
title: {
type: String,
default: ''
}
},
data() {
return {
curTime: 0,
percent: 0,
playState: 0,
hold: false,
progess: null,
max: 1000
}
},
watch: {
'percent': function (newVal) {
if (this.hold) {
clearTimeout(this.progess)
this.progess = setTimeout(() => {
this.$refs.player.currentTime = this.duration * newVal
this.hold = false
}, 300)
}
}
},
mounted() {
this.duration = parseInt(this.duration)
this.initPlayer()
},
methods: {
updateProgess(e) {
let ct = this.$refs.player.currentTime
this.curTime = parseInt(ct)
if (!this.hold) {
if (this.duration === 0) {
this.percent = 0
} else {
this.percent = this.curTime / this.duration
}
}
},
play() {
this.$nextTick(() => {
this.$refs.player.play()
this.playState = 1
if (typeof window.WeixinJSBridge !== 'undefined') {
window.WeixinJSBridge.invoke('getNetworkType', {}, e => {
this.$refs.player.play()
this.playState = 1
})
}
})
},
pause() {
this.$nextTick(() => {
this.$refs.player.pause()
this.playState = 2
if (typeof window.WeixinJSBridge !== 'undefined') {
window.WeixinJSBridge.invoke('getNetworkType', {}, e => {
this.$refs.player.pause()
this.playState = 2
})
}
})
},
showDuraTime(val) {
let m = Math.floor(val / 60)
let n = val - m * 60
return (m < 10 ? '0' + m : m) + ':' + (n < 10 ? '0' + n : n)
},
initPlayer() {
let dot = this.$refs.dot
let body = document.getElementsByTagName('body')[0]
let cw = parseFloat(
window.getComputedStyle(document.getElementsByTagName('body')[0]).width
)
dot.addEventListener(
'touchstart',
event => {
this.hold = true
},
false
)
body.addEventListener(
'touchend',
event => {
},
false
)
body.addEventListener(
'touchmove',
event => {
if (!this.hold) {
return false
}
var p = parseFloat(event.touches[0].pageX) / cw
this.percent = p > 1 ? 1 : p < 0 ? 0 : p
},
false
)
if (typeof window.WeixinJSBridge !== 'undefined') {
window.WeixinJSBridge.invoke('getNetworkType', {}, e => {
this.$refs.player.load()
})
} else {
this.$refs.player.load()
}
}
}
})
new Vue({
el: '#app'
})
<div id="app">
<player audioSrc="http://aikangcloudtest-new.oss-cn-qingdao.aliyuncs.com/audio/20191009144415866.mp3"
:duration="283" title="音乐"></player>
</div>
.audio-wrapper {
border: 1px solid #EFEFEF;
background: #FDFDFD;
display: flex;
align-items: center;
padding: 14px 20px;
margin-bottom: 14px;
}
.player {
position: absolute;
bottom: 0;
}
.player-btn {
width: 42px;
height: 42px;
border-radius: 50%;
border: solid 2px #775979;
display: flex;
align-items: center;
justify-content: center;
}
.player-btn .loading {
width: 28px;
height: 28px;
}
.player-btn .voice {
width: 20px;
height: 28px;;
}
.title {
margin-left: 20px;
font-size: 14px;
color: #000;
font-weight: 600;
}
.right {
flex: 1;
}
.audio-player {
flex: 1;
padding-left: 20px;
margin-top: 16px;
}
.time-wrapper {
display: flex;
justify-content: space-between;
padding-top: 6px;
}
.cur-time,
.duration {
font-size: 12px;
color: #9B9B9B;
}
.line {
height: 10px;
}
.slide-wrapper {
height: 2px;
background: #D8D8D8;
position: relative;
overflow: visible;
}
.slide-wrapper .line {
width: 0%;
height: 2px;
background: #775979;
position: absolute;
left: 0;
top: 0;
}
.slide-wrapper .dot {
width: 6px;
height: 6px;
position: absolute;
top: -4px;
right: -8px;
border: solid 2px #A799A8;
background: #775979;
border-radius: 50%;
z-index: 2;
}