uniapp使用uni.createInnerAudioContext()实现在app 小程序 h5有声书的播放

这篇具有很好参考价值的文章主要介绍了uniapp使用uni.createInnerAudioContext()实现在app 小程序 h5有声书的播放。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

实现读书软件的听书功能,适配app,小程序,h5

实现效果展示功能带你包括: 章节,倒计时,上一章,下一章,播放,暂停,倍速:
uniapp官方uni.createInnerAudioContext()的文档地址:官网文档参考地址
首先分步骤介绍功能:

  1. 章节(这个调取接口遍历数据就可以,弹出层的形式展示)
  2. 倒计时
  3. 上一章
  4. 下一章
  5. 播放
  6. 暂停
  7. 倍速

我这里页面嵌入一个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)
},

播放功能

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模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • uni-app实现自定义导航栏,兼容H5、App、微信小程序

    很多情况下,系统自带的导航栏无法满足UI设计的要求,这时候就需要我们自定义导航栏来实现需求,要考虑跨端的多种情况,这里我们封装成一个组件来使用,实现效果如下: 一、H5、App、微信小程序的区别 1.H5:导航栏高度可以设为44px,它没有状态栏,因为H5端运行在浏览

    2024年04月13日
    浏览(76)
  • uni-app 实现navigateBack返回修改前一页面数据(H5、APP、小程序)

    先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7 深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前! 因此收集整理了一份《2024年最新Web前端全套学习资料》,

    2024年04月29日
    浏览(69)
  • uni-app,关于 canvas 在 app,小程序, h5中,实现绘制,保存本地图片

    没有套路,没有难读的文档,直接看代码 html部分 js部分

    2024年02月13日
    浏览(63)
  • uni-app 使用webview加载H5打开微信小程序

    最近公司有个需求要求在app里点击一个功能打开小程序,并且关闭小程序回到app,模仿平安保险app。 毕竟我也是刚学习uni-app,找了很多资料,找到了一个天天外链的网站可以生成一个小程序的链接,使用uni的webview去加载这个链接,很好,需求满足,但是收费,那能不能自己

    2023年04月18日
    浏览(75)
  • 【微信小程序】使用uni-app——开发首页搜索框导航栏(可同时兼容APP、H5、小程序)

    目录 前言 App、H5效果 小程序效果 一、兼容APP、H5的方式 二、兼容小程序 三、实现同时兼容 首页都会提供一个搜索框给到客户,让客户自己去搜索自己想要的内容,这里就需要导航栏,来实现搜索页面的跳转,效果如下 在常见titleNView配置代码示例中可以看到基本样式的代码

    2024年02月03日
    浏览(79)
  • uniapp实现将页面转换成pdf(小程序、app、h5)

    使用html2Canvas和jspdf 安装这两个 uniapp在小程序无法获取dom,app端可在renderjs中获取 dom,小程序需要使用web-view导入一个h5页面,实现转pdf H5和小程序 其中通过web-view导入到微信小程序的话,需要导入微信的sdk 在index.html中导入也不知道咋回事,有wx,但是wx.miniProgram是undefined 然

    2024年02月08日
    浏览(50)
  • uniapp实现扫码功能H5+APP+wx小程序

    1.首先uniapp初始化(需要引入 npm包 已经初始化就忽略吧) 2.终端执行(需要引入vue-qrcode-reader)//只适用于vue2版本 3 创建一个扫码页面(用于其他页面往此页面跳转) 4.manifest.json配置H5 1.直接创建扫码页面(用于其他页面往此页面跳转) wx小程序

    2024年02月13日
    浏览(55)
  • uni-app(踩坑第三篇):音频Api之uni.createInnerAudioContext()

    uni.createInnerAudioContext() 创建并返回内部 audio 上下文  innerAudioContext  对象。 最近在写一个仿网易云的项目,使用uni.createInnerAudioContext()封装了一个音频组件 #myaudio.vue 主要实现了图片旋转以及音乐的播放和暂停 有没有大佬指教一番的让我涨涨知识 这是实现图片绕中心轴无限旋

    2024年02月15日
    浏览(70)
  • uni-app小程序实现音频播放,uniapp播放录音,uniapp简单实现播放录音

    复制到.vue文件即可预览效果 问题 :开发者工具中.onTimeUpdate方法可能会失效! 官方参考:https://uniapp.dcloud.net.cn/api/media/audio-context.html# 其他博客参考:https://blog.csdn.net/weixin_45328705/article/details/114091301 录音实现参考 :https://blog.csdn.net/weixin_43992507/article/details/129857780

    2024年02月12日
    浏览(84)
  • uniapp实现H5、APP、微信小程序三端文件下载

    这里我使用了uniapp官方api uni.downloadFile 和 uni.openDocument APP使用了uniapp官方api uni.downloadFile 和 uni.saveImageToPhotosAlbum(OBJECT) 还有 uni.openDocument H5的方法比较简单可以直接使用window.open方法下载。即: 如果你的浏览器支持预览,就会自动打开预览文件,然后自己手动下载文件,不支

    2024年02月16日
    浏览(73)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包