实现读书软件的听书功能,适配app,小程序,h5
实现效果展示功能带你包括: 章节,倒计时,上一章,下一章,播放,暂停,倍速:
uniapp官方uni.createInnerAudioContext()的文档地址:官网文档参考地址
首先分步骤介绍功能:
- 章节(这个调取接口遍历数据就可以,弹出层的形式展示)
- 倒计时
- 上一章
- 下一章
- 播放
- 暂停
- 倍速
我这里页面嵌入一个audio的组件 ,组件名称audio
components: {Audio},
data() {
return {
sourceList:[], //章节的数据
bookImg: '', //图书的封面图
bookName:'',//书名
chapterName: '', //章节名称
chapterUrl:'',//播放的章节地址
id: null, //书的id
itemId:'', //章节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的页面代码:
<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>
<!-- 倍速弹出层 -->
<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">
设置倒计时关闭
</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小时
</view>
<view class="rate-list" @click="handleCloseTime(2)">
2小时
</view>
</view>
</view>
</scroll-view>
</u-popup>
<!-- #ifdef APP-PLUS -->
<sharePop :shows="shows" :href="href" :title='title' @closes='closes'></sharePop>
<!-- #endif -->
</view>
</template>
首先进入页面初始化方法:
mounted() {
let that = this
that.initData()
},
initData() {
let that = this
// 页面加载设置当前播放章节的播放信息
this.bgAudioMannager = uni.createInnerAudioContext(); //只创建一次之后都是通过this.bgAudioMannager获取
this.bgAudioMannager.coverImgUrl = this.bookImg
this.bgAudioMannager.title = this.chapterName
this.bgAudioMannager.src = this.chapterUrl
// this.bgAudioMannager.playbackRate = 1.0 默认倍速为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(() => {
//初始化 需要的参数
console.log('自然播放结束事件');
// this.nextMusic()
});
this.bgAudioMannager.onError((res) => {
console.log(res.errMsg);
console.log(res.errCode);
});
// 重要 缺失 音频进入可以播放状态
this.bgAudioMannager.onCanplay(() => {
this.currentTime = this.bgAudioMannager.currentTime
this.duration = this.bgAudioMannager.duration
console.log("可播放状态")
if (this.bgAudioMannager.duration) {
this.duration = this.bgAudioMannager.duration
console.log(this.bgAudioMannager.duration)
}
})
this.bgAudioMannager.play()
//音频进度更新事件
this.bgAudioMannager.onTimeUpdate(() => {
// console.log("开始监听")
/*
判断是否点击过进度条,若点击过,则不要对当前进度条时间current赋currentTime的值
因为音频进度更新事件运行频率过快,两个时间会引起冲突,
因此需要通过设置开关,判断seek真假,若seek为假则未点击进度条,若seek为真则跳过此次赋值并修改seek值重置为假
*/
if (!this.seek) {
this.currentTime = this.bgAudioMannager.currentTime
} else {
console.log("修改一次进度条")
// 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('播放结束')
this.nextMusic()
});
},
如果需要页面返回的时候暂停音频:
onUnload() {
// clearInterval(timeSet); //停止调用
this.bgAudioMannager.pause()
this.newTime = 0;
this.playStatus = false //暂停播放的状态
this.bgAudioMannager.src = '' //当设置了新的 src 时,会自动开始播放
},
destroyed() {
this.bgAudioMannager.pause()
this.endTime = this.getDate()
},
点击进度条跳转到指定位置:
// 点击进度条
clickSeek(val) {
this.currentTime = val
this.bgAudioMannager.seek(val)
},
播放功能文章来源:https://www.toymoban.com/news/detail-502773.html
playOrpause() {
//根据播放状态进行播放还是暂停
if (this.playStatus) {
this.bgAudioMannager.pause()
this.playStatus = false
} else {
this.bgAudioMannager.play()
this.playStatus = true
}
},
上一章和下一章,我们的章节目录结构是两层,逻辑是根据点击的进来的章节id去章节数组中找对应的章节,然后取他的上一节点或者下一节点,注意点:要把拿到的id替换掉当前的id文章来源地址https://www.toymoban.com/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) => {
//看当前id是否在子章节当中
currentIdx = item.twoLevelChapter.findIndex((item1) => item1.id == this.id)
lastIndex = item.twoLevelChapter.length - 1
//如果在父章节中找到,直接拿当前章节上一章节,通过下标-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 {
//如果刚好拿到的是第一章节就直接给提示
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: '没有上一章节了',
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: '已经是第一章了',
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: '已经是最后一章了',
icon: 'none'
})
return
}
}
//如果播放自动播放完就自动切换下一章
this.bgAudioMannager.onEnded(() => {
//初始化 需要的参数
console.log('自然播放结束eee事件');
this.nextMusic()
});
},
到了这里,关于uniapp使用uni.createInnerAudioContext()实现在app 小程序 h5有声书的播放的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!