實(shí)現(xiàn)讀書軟件的聽書功能,適配app,小程序,h5
實(shí)現(xiàn)效果展示功能帶你包括: 章節(jié),倒計(jì)時(shí),上一章,下一章,播放,暫停,倍速:
uniapp官方uni.createInnerAudioContext()的文檔地址:官網(wǎng)文檔參考地址
首先分步驟介紹功能:
- 章節(jié)(這個(gè)調(diào)取接口遍歷數(shù)據(jù)就可以,彈出層的形式展示)
- 倒計(jì)時(shí)
- 上一章
- 下一章
- 播放
- 暫停
- 倍速
我這里頁(yè)面嵌入一個(gè)audio的組件 ,組件名稱audio
components: {Audio},
data() {
return {
sourceList:[], //章節(jié)的數(shù)據(jù)
bookImg: '', //圖書的封面圖
bookName:'',//書名
chapterName: '', //章節(jié)名稱
chapterUrl:'',//播放的章節(jié)地址
id: null, //書的id
itemId:'', //章節(jié)id
}
},
<template>
<view class="content">
<view class="" v-if="sourceList.length > 0">
<Audio @handleId='handleId' :sourceList='sourceList' :bookResourceId='bookResourceId' :bookName='bookName' :bookImg='bookImg' :id='id' :wxId='id' :chapterName='chapterName' :chapterUrl='chapterUrl'></Audio>
</view>
</view>
</template>
handleId(id){
this.id = id
},
Audio的頁(yè)面代碼:
<template>
<view class="audio_content">
<view class="audio_box">
<image class="audio-img" :src="bookImg" mode="aspectFill"></image>
<view class="img-pop">
</view>
<view class="audio-info">
<!-- #ifdef APP-PLUS -->
<view class="header-box">
<u-icon name="arrow-left" style="margin-left: 32rpx;" color="#ffffff" size="24"
@click="goBack()"></u-icon>
<u-icon style="margin-right: 44rpx;" name="share-square" color="#ffffff" size="24"
@click="appShare"></u-icon>
</view>
<!-- #endif -->
<view class="course_name">
{{bookName}}
</view>
<view class="audio_title">
{{bgAudioMannager.title}}
<!-- {{bookTitle}} -->
</view>
<view class="book-box">
<image class="book-img" :src="bookImg" mode="aspectFill"></image>
</view>
<view class="audio_process">
<view class='slider'>
<!-- <slider :value="currentTime" step="1" min="0" :max="duration"
block-color="#fff" activeColor="#DC3232" inactiveColor="#8B8D7F" block-size="12"
@change="seek=true,clickSeek($event.detail.value)" @changing="seek=true,current=$event.detail.value" /> -->
<slider class="audio-slider" activeColor="#DC3232" block-size="12" :value="currentTime"
:max="duration" @changing="seek=true,current=$event.detail.value"
@change="seek=true,clickSeek($event.detail.value)"></slider>
</view>
<view class="time_cons">
<view class="duration">
{{ time.getAudioTime(currentTime) }}
</view>
<view class="end">
{{ time.getAudioTime(duration) }}
</view>
</view>
</view>
<view class="utils">
<view @tap="showModal">
<image class="change-list" :src="$staticUrl + 'static/index/audio-list.png'" mode="">
</image>
</view>
<view class="timeBox" @click="openTime">
<image class="change-time" :src="$staticUrl + 'static/index/audio-time.png'" mode="">
</image>
<view class="timeText">
{{timeMsg}}
</view>
</view>
<!-- 上一章 -->
<view class="">
<image v-if="!lastPlay" @click="lastMusic" class="change"
:src="$staticUrl + 'static/audio.png'" />
<image @click="lastMusic" class="change" v-if="lastPlay"
:src="$staticUrl + 'static/index/audio-pre.png'" />
</view>
<!-- 播放 -->
<view class="">
<image @click="playOrpause" v-if="!playStatus" class="change-start"
:src="$staticUrl + 'static/index/audio-start.png'" />
<image @tap="playOrpause" v-if="playStatus" class="change-start"
:src="$staticUrl + 'static/index/jgq_sxzt.png'" />
</view>
<!-- 下一章 -->
<view class="prev next">
<image @click="nextMusic" v-if="nextPlay" class="change"
:src="$staticUrl + 'static/index/audio-next.png'" />
<image v-if="!nextPlay" class="change" :src="$staticUrl + 'static/audio-g.png'" />
</view>
<view class="beisu" @click="showPlaybackRate = true">
<text class="num">{{rateText}}</text>
<!-- <text class="text">倍速播放</text> -->
</view>
</view>
</view>
</view>
<u-popup :show="hideModal" @close="close" @open="open" :round="10">
<!-- <view class="empty-box" id="empty-box"></view> -->
<scroll-view scroll-y style="height: 100%;">
<view class="content" :style="'transform:translateY(' + translateY + 'px);'" :animation="animate">
<view class="header">
<view class="title">
目錄
</view>
<view class="right" @click="close">
<u-icon name="close" color="#000000" size="20"></u-icon>
</view>
</view>
<view>
<PeriodList :bookCoverImg='bookImg' :bookName='bookName' :supCode='supCode'
:sourceType='sourceType' :id='id' type='audio' :chapterList='sourceList'
@startAudio='startAudio' :bookResourceId='bookResourceId'></PeriodList>
</view>
</view>
</scroll-view>
</u-popup>
<!-- 倍速?gòu)棾鰧?-->
<u-popup :show="showPlaybackRate" @close="closePlaybackRate" @open="openPlaybackRate" :round="10">
<!-- <view class="empty-box" id="empty-box"></view> -->
<scroll-view scroll-y style="height: 100%;">
<view class="content" :style="'transform:translateY(' + translateY + 'px);'" :animation="animate">
<view class="header">
<view class="title">
倍速選擇
</view>
<view class="right" @click="closePlaybackRate">
<u-icon name="close" color="#000000" size="20"></u-icon>
</view>
</view>
<view class="rate-listBox">
<view class="rate-list" @click="handleRate(0.5)">
0.5倍速
</view>
<view class="rate-list" @click="handleRate(1)">
1.0倍速
</view>
<view class="rate-list" @click="handleRate(1.5)">
1.5倍速
</view>
<view class="rate-list" @click="handleRate(2.0)">
2.0倍速
</view>
</view>
</view>
</scroll-view>
</u-popup>
<u-popup :show="showCloseTime" @close="closeTime" @open="openTime" :round="10">
<!-- <view class="empty-box" id="empty-box"></view> -->
<scroll-view scroll-y style="height: 100%;">
<view class="content" :style="'transform:translateY(' + translateY + 'px);'" :animation="animate">
<view class="header">
<view class="title">
設(shè)置倒計(jì)時(shí)關(guān)閉
</view>
<view class="right" @click="closeTime">
<u-icon name="close" color="#000000" size="20"></u-icon>
</view>
</view>
<view class="rate-listBox">
<!-- <view class="rate-list" @click="handleCloseTime(11)">
1分鐘
</view>
<view class="rate-list" @click="handleCloseTime(12)">
5分鐘
</view> -->
<view class="rate-list" @click="handleCloseTime(15)">
15分鐘
</view>
<view class="rate-list" @click="handleCloseTime(30)">
30分鐘
</view>
<view class="rate-list" @click="handleCloseTime(45)">
45分鐘
</view>
<view class="rate-list" @click="handleCloseTime(1)">
1小時(shí)
</view>
<view class="rate-list" @click="handleCloseTime(2)">
2小時(shí)
</view>
</view>
</view>
</scroll-view>
</u-popup>
<!-- #ifdef APP-PLUS -->
<sharePop :shows="shows" :href="href" :title='title' @closes='closes'></sharePop>
<!-- #endif -->
</view>
</template>
首先進(jìn)入頁(yè)面初始化方法:
mounted() {
let that = this
that.initData()
},
initData() {
let that = this
// 頁(yè)面加載設(shè)置當(dāng)前播放章節(jié)的播放信息
this.bgAudioMannager = uni.createInnerAudioContext(); //只創(chuàng)建一次之后都是通過this.bgAudioMannager獲取
this.bgAudioMannager.coverImgUrl = this.bookImg
this.bgAudioMannager.title = this.chapterName
this.bgAudioMannager.src = this.chapterUrl
// this.bgAudioMannager.playbackRate = 1.0 默認(rèn)倍速為1.0
this.newId = this.id
this.duration = this.bgAudioMannager.duration
this.currentTime = this.bgAudioMannager.currentTime
this.currentId = this.id
this.startTime = this.getDate()
this.bgAudioMannager.onPlay(() => {
console.log('開始播放');
});
this.bgAudioMannager.onStop(() => {
console.log('停止播放');
});
this.bgAudioMannager.onPause(() => {
console.log('暫停播放');
});
this.bgAudioMannager.onEnded(() => {
//初始化 需要的參數(shù)
console.log('自然播放結(jié)束事件');
// this.nextMusic()
});
this.bgAudioMannager.onError((res) => {
console.log(res.errMsg);
console.log(res.errCode);
});
// 重要 缺失 音頻進(jìn)入可以播放狀態(tài)
this.bgAudioMannager.onCanplay(() => {
this.currentTime = this.bgAudioMannager.currentTime
this.duration = this.bgAudioMannager.duration
console.log("可播放狀態(tài)")
if (this.bgAudioMannager.duration) {
this.duration = this.bgAudioMannager.duration
console.log(this.bgAudioMannager.duration)
}
})
this.bgAudioMannager.play()
//音頻進(jìn)度更新事件
this.bgAudioMannager.onTimeUpdate(() => {
// console.log("開始監(jiān)聽")
/*
判斷是否點(diǎn)擊過進(jìn)度條,若點(diǎn)擊過,則不要對(duì)當(dāng)前進(jìn)度條時(shí)間current賦currentTime的值
因?yàn)橐纛l進(jìn)度更新事件運(yùn)行頻率過快,兩個(gè)時(shí)間會(huì)引起沖突,
因此需要通過設(shè)置開關(guān),判斷seek真假,若seek為假則未點(diǎn)擊進(jìn)度條,若seek為真則跳過此次賦值并修改seek值重置為假
*/
if (!this.seek) {
this.currentTime = this.bgAudioMannager.currentTime
} else {
console.log("修改一次進(jìn)度條")
// this.audio.seek(this.current_tmp)
// this.current = this.current_tmp
console.log(this.currentTime)
this.seek = false
}
if (this.bgAudioMannager.duration) {
this.duration = this.bgAudioMannager.duration
}
})
this.bgAudioMannager.onEnded(() => {
console.log('播放結(jié)束')
this.nextMusic()
});
},
如果需要頁(yè)面返回的時(shí)候暫停音頻:
onUnload() {
// clearInterval(timeSet); //停止調(diào)用
this.bgAudioMannager.pause()
this.newTime = 0;
this.playStatus = false //暫停播放的狀態(tài)
this.bgAudioMannager.src = '' //當(dāng)設(shè)置了新的 src 時(shí),會(huì)自動(dòng)開始播放
},
destroyed() {
this.bgAudioMannager.pause()
this.endTime = this.getDate()
},
點(diǎn)擊進(jìn)度條跳轉(zhuǎn)到指定位置:
// 點(diǎn)擊進(jìn)度條
clickSeek(val) {
this.currentTime = val
this.bgAudioMannager.seek(val)
},
播放功能文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-502773.html
playOrpause() {
//根據(jù)播放狀態(tài)進(jìn)行播放還是暫停
if (this.playStatus) {
this.bgAudioMannager.pause()
this.playStatus = false
} else {
this.bgAudioMannager.play()
this.playStatus = true
}
},
上一章和下一章,我們的章節(jié)目錄結(jié)構(gòu)是兩層,邏輯是根據(jù)點(diǎn)擊的進(jìn)來(lái)的章節(jié)id去章節(jié)數(shù)組中找對(duì)應(yīng)的章節(jié),然后取他的上一節(jié)點(diǎn)或者下一節(jié)點(diǎn),注意點(diǎn):要把拿到的id替換掉當(dāng)前的id文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-502773.html
//上一首
lastMusic() {
let that = this
var currentIndex = null
var lastIndex = null
var currentIdx = null
this.bgAudioMannager.pause()
currentIndex = this.sourceList.findIndex((profile) => profile.id == that.id)
if (currentIndex == null || currentIndex == -1) {
this.sourceList.forEach((item, index) => {
//看當(dāng)前id是否在子章節(jié)當(dāng)中
currentIdx = item.twoLevelChapter.findIndex((item1) => item1.id == this.id)
lastIndex = item.twoLevelChapter.length - 1
//如果在父章節(jié)中找到,直接拿當(dāng)前章節(jié)上一章節(jié),通過下標(biāo)-1的信息
if (currentIdx != -1) {
if (currentIdx != 0) {
this.bgAudioMannager.title = item.twoLevelChapter[currentIdx - 1].chapterName
this.bgAudioMannager.coverImgUrl = item.twoLevelChapter[currentIdx - 1].chapterUrl
this.bgAudioMannager.src = item.twoLevelChapter[currentIdx - 1].chapterUrl
that.newId = item.twoLevelChapter[currentIdx - 1].id
that.$emit('handleId', this.newId)
this.nextPlay = true
this.playStatus = true
this.bgAudioMannager.play()
} else {
//如果剛好拿到的是第一章節(jié)就直接給提示
if (index == 0) {
this.bgAudioMannager.title = item.twoLevelChapter[0].chapterName
this.bgAudioMannager.coverImgUrl = item.twoLevelChapter[0].chapterUrl
this.bgAudioMannager.src = item.twoLevelChapter[0].chapterUrl
that.newId = item.twoLevelChapter[0].id
uni.showToast({
title: '沒有上一章節(jié)了',
icon: 'none'
})
return
} else {
this.bgAudioMannager.title = that.sourceList[index - 1].chapterName
this.bgAudioMannager.coverImgUrl = that.sourceList[index - 1].coverImgUrl
this.bgAudioMannager.src = that.sourceList[index - 1].chapterUrl
that.newId = that.sourceList[index - 1].id
that.$emit('handleId', this.newId)
}
}
}
})
} else {
lastIndex = this.sourceList.length - 1
if (currentIndex != 0) {
this.bgAudioMannager.title = that.sourceList[currentIndex - 1].chapterName
this.bookTitle = this.bgAudioMannager.title
console.log('title', this.bgAudioMannager.title)
this.bgAudioMannager.coverImgUrl = this.sourceList[currentIndex - 1].coverImgUrl
this.bgAudioMannager.src = this.sourceList[currentIndex - 1].chapterUrl
this.newId = this.sourceList[currentIndex - 1].id
that.$emit('handleId', this.newId)
this.nextPlay = true
this.playStatus = true
this.bgAudioMannager.play()
} else {
this.bgAudioMannager.title = that.sourceList[0].chapterName
this.bgAudioMannager.src = this.sourceList[0].chapterUrl
this.newId = this.sourceList[0].id
this.bgAudioMannager.play()
uni.showToast({
title: '已經(jīng)是第一章了',
icon: 'none'
})
return
}
}
this.id = this.newId
},
// 下一首
nextMusic() {
let that = this
var currentIndex = null
var lastIndex = null
var currentIdx = null
this.bgAudioMannager.pause()
currentIndex = this.sourceList.findIndex((profile) => profile.id == this.id)
if (currentIndex == null || currentIndex == -1) {
this.sourceList.forEach(item => {
currentIdx = item.twoLevelChapter.findIndex((item1) => item1.id == this.id)
lastIndex = item.twoLevelChapter.length - 1
if (currentIdx != -1) {
if (currentIdx != lastIndex) {
this.bgAudioMannager.title = item.twoLevelChapter[currentIdx + 1].chapterName
this.bgAudioMannager.coverImgUrl = item.twoLevelChapter[currentIdx + 1].chapterUrl
this.bgAudioMannager.src = item.twoLevelChapter[currentIdx + 1].chapterUrl
this.id = item.twoLevelChapter[currentIdx + 1].id
this.nextPlay = true
this.playStatus = true
this.bgAudioMannager.play()
} else {
this.bgAudioMannager.title = that.sourceList[currentIndex + 1].chapterName
this.bgAudioMannager.coverImgUrl = that.sourceList[currentIndex + 1].chapterUrl
this.bgAudioMannager.src = that.sourceList[currentIndex + 1].chapterUrl
that.id = that.sourceList[currentIndex + 1].id
this.bgAudioMannager.play()
}
}
})
} else {
lastIndex = this.sourceList.length - 1
if (currentIndex != lastIndex) {
this.bgAudioMannager.title = this.sourceList[currentIndex + 1].chapterName
this.bgAudioMannager.coverImgUrl = this.sourceList[currentIndex + 1].chapterUrl
this.bgAudioMannager.src = this.sourceList[currentIndex + 1].chapterUrl
this.id = this.sourceList[currentIndex + 1].id
this.nextPlay = true
this.playStatus = true
this.bgAudioMannager.play()
} else {
this.bgAudioMannager.title = this.sourceList[lastIndex].chapterName
this.bgAudioMannager.coverImgUrl = this.sourceList[lastIndex].chapterUrl
this.bgAudioMannager.src = this.sourceList[lastIndex].chapterUrl
this.id = this.sourceList[lastIndex].id
this.bgAudioMannager.play()
uni.showToast({
title: '已經(jīng)是最后一章了',
icon: 'none'
})
return
}
}
//如果播放自動(dòng)播放完就自動(dòng)切換下一章
this.bgAudioMannager.onEnded(() => {
//初始化 需要的參數(shù)
console.log('自然播放結(jié)束eee事件');
this.nextMusic()
});
},
到了這里,關(guān)于uniapp使用uni.createInnerAudioContext()實(shí)現(xiàn)在app 小程序 h5有聲書的播放的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!