uniapp自定义播放器

news2024/11/26 19:28:36

问题描述:我是真无语啊,就是有一个目录切换的地方,然后切换音频,结果你猜怎么着,嘿,音频他不播放了。也就是下面这个方法都不进去了打印的时候,音频播放都播放不了了,我尝试了销毁在播也不行。然后我寻思着,我写代码相同的我也喜欢return出去,会不会是这个原因,结果抱着试一试的态度,好家伙,真这样。

解决方法:在后台设置的时候,换成两个不同的音频进行切换就完事了。一般测试阶段才会出现,我觉得正式用,人家也不会放两个相同的视频在一个课程里面把,并且呢,这个在h5是好的,小程序才会出现。

代码:

<template>
	<view class="wrap" v-if="!loadding">
		<view class="videoWrap">
			<view class="videoBox">
				<template v-if="!videoPause">
					<view class="masterPic">
						<image class="img" :src="detail.video_image" mode="scaleToFill"></image>
					</view>
					<image class="startIcon" src="/static/image/bofang.png" mode="scaleToFill"  @click="startVideo"></image>
				</template>
				<template v-else>
					<video id="video" :src="detail.video_link" :autoplay="true" style="width: 100%;height: 100%"></video>
				</template>
			</view>
			<view class="contnet">
				<view class="title">{{ detail.title }}</view>
				<!-- <view class="num">视频已播放2596次</view> -->
				<view class="num">{{ detail.update_time }}</view>
			</view>
		</view>
		<view class="auditorWrap" v-if="detail.audio_image">
			<image class="imgAuditor" :src="detail.audio_image" mode="scaleToFill"></image>
			<view class="contnet">
				<view class="title">{{ detail.title }}</view>
				<view class="num">{{ detail.update_time }}</view>
			</view>
			<view class="auditorBox">
				<view class="iconList">
					<image class="icon" src="/static/image/bofang1.png" mode="scaleToFill" v-if="!status" @click="changeto"></image>
					<image class="icon" src="/static/image/zanting.png" mode="scaleToFill" v-else  @click="changeto"></image>
				</view>
				<view class="progressBox">
					<view class="progress">
						<view class="activeProgress" :style="{width:`${progress}%`}">
							<view class="activeRightBox">
								<view class="circle" v-show="progress > 0"></view>
							</view>
						</view>
					</view>
					<view class="timeBox">
						<view>{{ formatTime(currentTime) }}</view>
						<view>{{ formatTime(duration) }}</view>
					</view>
				</view>
			</view>
		</view>
		<view class="intro" v-if="detail.content">
			<view v-html="detail.content"></view>
		</view>
		<movable-area class="recordWrap">
			<movable-view :x="removeArea.x" :y="removeArea.y" direction="all" class="record">
				<view @click.stop="gotoRecourd">
					<image class="img" src="/static/image/recourdIcon.png" mode="scaleToFill"></image>
					<view class="label">课程目录</view>
				</view>
			</movable-view>
		</movable-area>
		<recourdVue :list="course.section" ref="recourdRef" />
	</view>
</template>

<script>
import utils from '@/common/utils.js';
import recourdVue from './part/recourd.vue';
const innerAudioContext = uni.createInnerAudioContext();
export default {
	components: {
		recourdVue
	},
	data() {
		return {
			/*商品id*/
			section_id: null,
			course_id: null,
			course: {},
			/*商品详情*/
			detail: {},
			status: false,
			beforeAudio: true,
			duration: 0,
			currentTime: 0,
			progress: 0,
			xpjAudio: null,
			videoPause: false,
			videoContext: null,
			removeArea:{
				x: 0,
				y: 0,
			}
		};
	},
	onReady() {
		console.log("onReady")
		this.videoContext = uni.createVideoContext('video', this);
	},
	onLoad(e) {
		console.log("onLoad")
		this.videoPause = false;
		/*商品id*/
		let scene = utils.getSceneData(e);
		this.section_id = e.section_id ? e.section_id : scene.sid;
		this.course_id = e.course_id ? e.course_id : scene.cid;
		this.getSystemInfo();
	},
	mounted() {
		console.log("mounted") 
		/*获取产品详情*/
		this.getData();
	},
	methods: {
		getSystemInfo(){
			let self = this;
			uni.getSystemInfo({
				success(res) {
					self.removeArea.x = res.windowWidth - 70;
					self.removeArea.y = res.windowHeight - 120;
				}
			});
		},
		initAudit(){
			innerAudioContext.src = this.detail.audio_link;
			this.getAudioInfo();
		},
		getAudioInfo(){
			innerAudioContext.onCanplay(()=>{
				innerAudioContext.duration;
				setTimeout(() => {
					this.duration = innerAudioContext.duration;
					this.watchAuditTime();
				});
			})
		},
		watchAuditTime(){
			innerAudioContext.onTimeUpdate(() => {
				const { currentTime,duration} = innerAudioContext;
				this.currentTime = currentTime;
				if(this.duration == this.currentTime){
					this.progress = 100;
					this.status = false;
				}else{
					this.progress = currentTime/duration * 100;
				}
			});
		},
		gotoRecourd(){
			this.$refs.recourdRef.open(
				{
					section_id: this.section_id,
					course_id: this.course_id,
				}
			);
		},
		startVideo(){
			this.videoPause = true;
			this.$nextTick(()=>{
				this.videoContext.play();
			})
		},
		changeto(){
			this.status = !this.status;
			if (this.status) {
				innerAudioContext.play();
				innerAudioContext.onPlay(() => {
					// 播放监听
					console.log('播放!');
				});
			} else {
				innerAudioContext.pause()
				this.currenttime = innerAudioContext.currentTime
			}
		},
		/*获取数据*/
		getData() {
			let self = this;
			let section_id = self.section_id;
			let course_id = self.course_id;
			self.loadding = true;
			uni.showLoading({
				title: '加载中'
			});
			self._get(
				'course.course/sectionDetail', {
				course_id: course_id,
				section_id: section_id,
			},
				function (res) {
					const { data: { detail: { course, detail } } } = res;
					self.course = course;
					self.detail = detail;
					self.initAudit();
					self.loadding = false;
					uni.hideLoading();
				},
				function (err) {

				}
			);
		},
		changeSwiper() {
			this.isVideoPlay = false;
		},
		formatTime(num) {
			num = Math.floor(num)
			let second = num % 60;
			if (second < 10) second = '0' + second;
			let min = Math.floor(num / 60);
			if (min < 10) min = '0' + min;
			return min + ":" + second;
		},
	}
};
</script>

<style lang="scss" scoped>
.videoWrap,.auditorWrap {
	background: #fff;

	.videoBox,.imgAuditor {
		width: 100%;
		height: 564rpx;
		position: relative;

		.masterPic {
			height: 100%;

			&::before {
				content: "";
				position: absolute;
				top: 0;
				left: 0;
				background: rgb(0, 0, 0, 0.45);
				width: 100%;
				height: 100%;
				z-index: 1;
			}

			.img {
				width: 100%;
				height: 100%;
			}
		}

		.startIcon {
			position: absolute;
			left: 50%;
			top: 50%;
			transform: translate(-50%, -50%);
			width: 92rpx;
			height: 92rpx;
			z-index: 10;
		}
	}
	.contnet{
		padding: 28rpx;
		.title{
			font-size: 32rpx;
			color: #333333;
			margin-bottom: 20rpx;
		}
		.num{
			font-size: 23rpx;
			color: #999999;
		}
	}

}
.auditorWrap{
	margin-top: 20rpx;
}
.auditorBox{
	display: flex;
	gap: 16rpx;
	padding: 28rpx;
	.iconList{
		width: 62rpx;
		height: 62rpx;
		.icon{
			width: 100%;
			height: 100%;
		}
	}
	.progressBox{
		flex: 1;
	}
	.progress{
		width: 100%;
		height: 20rpx;
		background: #EDE8E8;
		border-radius: 20rpx;
		position: relative;
		.activeProgress{
			position: absolute;
			left: 0;
			top: 0;
			background: #F2473F;
			height: 100%;
			border-radius: 20rpx;
			transition: width 1s ease;
			.activeRightBox{
				position: relative;
				height: 100%;
				.circle{
					width: 42rpx;
					height: 42rpx;
					background: #FFFFFF;
					border: 2rpx solid #F2473F;
					box-shadow: 0px 5rpx 5rpx 0px rgba(0,0,0,0.1);
					border-radius: 50%;
					position: absolute;
					right: 0;
					top: -12rpx;
				}
			}
		}
	}
	.timeBox{
		display: flex;
		justify-content: space-between;
		color: #F2473F;
		font-size: 32rpx;
		padding-top: 8rpx;
	}
}
.intro{
	margin-top: 20rpx;
	padding: 28rpx;
	background: #fff;
}
.recordWrap{
	position: fixed;
	bottom: 0;
	top: 0;
	width: 100vw;
	height: 100vh;
	pointer-events: none;
}
.record{
	width: 111rpx;
	height: 111rpx;
	background: linear-gradient(45deg, #F2473F, #F26E2F);
	border-radius: 50%;
	position: relative;
	pointer-events: visible;
	.img{
		width: 54rpx;
		height: 53rpx;
		position: absolute;
		top: 40%;
		left: 50%;
		transform: translate(-50%,-50%);
	}
	.label{
		width: 131rpx;
		height: 43rpx;
		line-height: 43rpx;
		background: linear-gradient(45deg, #F2473F, #F26E2F);
		box-shadow: 0px 5rpx 5rpx 0px rgba(9,2,4,0.25);
		font-size: 26rpx;
		color: #fff;
		text-align: center;
		position: absolute;
		bottom: -10rpx;
		left: -8rpx;
		border-radius: 20rpx;
	}
}
</style>

recourd.vue 子组件

<template>
    <view class="recourdMask" v-if="show">
        <view class="recourdBox">
            <view class="closeIcon" @click="closeIcon">
                <u-icon name="close" color="#424242" size="40rpx"></u-icon>
            </view>
            <view class="title">课程目录</view>
            <scroll-view :scroll-top="scrollTop" :scroll-y="true" class="content" scroll-with-animation="true">
                <view class="list">
                    <view class="item" v-for="v in list" :key="v" @click="gotoLook(v)">
                        <view class="txt">{{ v.title }}</view>
                        <view class="status" v-if="v.is_see == 1">试学</view>
                    </view>
                </view>
            </scroll-view>
        </view>
    </view>
</template>

<script>
	export default {
        props: {
            list: {
                type: Array,
                default: [],
            }
        },
		components: {},
		data() {
			return {
                params: {},
                show: false,
			}
		},
		methods: {
            open(params){
                this.params = params;
                this.show = true;
            },
            gotoLook(v){
                if(v.payStatus == 0 || v.is_see == 0){
                    uni.showToast({
                        icon: 'none',
                        title: '此章节需要购买后查看'
                    });
                    return
                }
                this.params.section_id = v.section_id;
                this.gotoPage(`pages/knowledge/course/section-detail?section_id=${this.params.section_id}&course_id=${this.params.course_id}`,'redirect');  
            },
            closeIcon(){
                this.show = false;
            }
        }
	}
</script>

<style lang="scss">
.recourdMask{
    position: fixed;
    bottom: 0;
    background: rgba(0,0,0,0.45);
    top: 0;
    width: 100%;
    height: 100%;
    z-index: 10;
    .recourdBox{
        position: fixed;
        bottom: 0;
        height: 882rpx;
        background: #fff;
        width: 100%;
        border-top-left-radius: 20rpx;
        border-top-right-radius: 20rpx;
        z-index: 2;
        .list{
            padding: 20rpx;
            padding-top: 0;
            box-sizing: border-box;
            .item{
                display: flex;
                justify-content: space-between;
                align-items: center;
                background: #F5F6F8;
                padding: 26rpx 22rpx;
                box-sizing: border-box;
                border-radius: 20rpx;
                margin-bottom: 20rpx;
            }
        }
        .title{
            font-size: 32rpx;
            font-weight: bold;
            color: #333333;
            text-align: center;
            height: 124rpx;
            line-height: 124rpx;
        }
        .status{
            width: 112rpx;
            height: 48rpx;
            text-align: center;
            line-height: 48rpx;
            background: rgba(249,156,49,0.15);
            font-size: 22rpx;
            color: #F2473F;
            border-radius: 20rpx;
        }
        .txt{
            font-size: 26rpx;
            color: #666666;
        }
    }
    .content{
        height: 882rpx;
    }
    .closeIcon{
        position: absolute;
        right: 28rpx;
        top: 28rpx;
    }
}
</style>

实现效果

目前呢,这个播放器还没有做拖动的。这个得后续优化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1029085.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端提交规范 ESLint + Prettier + husky + lint-staged

如何统一代码风格&#xff0c;规范提交呢&#xff1f; 推荐使用前端规范全家桶 ESLint Prettier husky lint-staged。 eslint (github.com/eslint/esli…)JavaScript 代码检测工具&#xff0c;检测并提示错误或警告信息prettier (github.com/prettier/pr…) 代码自动化格式…

【面试题】Js数组去重都有哪些方法?

前端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 表妹一键制作自己的五星红旗国庆头像&#xff0c;超好看 1. indexOf 定义&#xff1a; indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置…

基于SSM的田径运动会成绩管理系统的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

秒懂生成式AI—大语言模型是如何生成内容的?

备受关注的大语言模型&#xff0c;核心是自然语言的理解与文本内容的生成&#xff0c;对于此&#xff0c;你是否好奇过它们究竟是如何理解自然语言并生成内容的&#xff0c;其工作原理又是什么呢&#xff1f; 要想了解这个&#xff0c;我们就不得不先跳出大语言模型的领域&…

Hadoop初识及信息安全(大数据的分布式存储和计算平台)

目录 什么是Hadoop Hadoop的特点 Hadoop优点 Hadoop的缺点 Hadoop的重要组成 信息安全 什么是Hadoop Hadoop 是一个适合大数据的分布式存储和计算平台。 Hadoop的广义和狭义区分&#xff1a; 狭义的Hadoop:指的是一个框架&#xff0c;Hadoop是由三部分组成&#xff1a;H…

做测试半年,我已经掉了4个坑……

从事软件测试工作已经半年多了&#xff0c;刚入职的时候还是一个缺乏实际经验的小白&#xff0c;而现在拿到需求之后也能比较快速地熟悉业务并顺利开展测试&#xff0c;虽然不能说掌握了很多技能&#xff0c;但是相比之前也是有不少收获的&#xff0c;在这个过程中我总结了一点…

使用vue-cli搭建SPA项目

一.SPA项目的构建 前提 nodeJS环境已经搭建完毕 node -v npm -v 什么是SPA项目 SPA&#xff08;Single Page Application&#xff09;项目是一种使用单页面架构的Web应用项目。在SPA项目中&#xff0c;整个应用程序只有一个HTML页面&#xff0c;通过动态加载数据和更新DOM来实…

计算机竞赛 深度学习+opencv+python实现昆虫识别 -图像识别 昆虫识别

文章目录 0 前言1 课题背景2 具体实现3 数据收集和处理3 卷积神经网络2.1卷积层2.2 池化层2.3 激活函数&#xff1a;2.4 全连接层2.5 使用tensorflow中keras模块实现卷积神经网络 4 MobileNetV2网络5 损失函数softmax 交叉熵5.1 softmax函数5.2 交叉熵损失函数 6 优化器SGD7 学…

springboot实现发送邮箱验证码

准备工作 在邮箱官网开放SMTP授权&#xff0c;获取相应密钥&#xff0c;才可以进行发送邮件 这里以网易163邮箱为例&#xff0c;登录邮箱后&#xff0c;依次点击“设置-POP3/SMTP/IMAP” &#xff0c;然后开启SMTP服务。这时候会提示一个授权码&#xff0c;例如&#xff1a;H…

I2C子系统、读取温湿度的逻辑及代码

一、IIC子系统 两根线&#xff1a; scl:时钟线 sda:数据线 iic有4种信号&#xff1a; 起始信号&#xff08;start&#xff09;:scl是高电平&#xff0c;sda下降沿 终止信号&#xff08;stop&#xff09;:scl高电平&#xff0c;sda上升沿 应答信号&#xf…

面试官:说说JavaScript中的数据类型?区别?

&#x1f3ac; 岸边的风&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 一、概述 二、显示转换 Number() parseInt() String() Boolean() 三、隐式转换 自动转换为布尔值 自动转换…

SOLIDWORKS2024新功能--SOLIDWORKS篇(二)

该章节包括以下主题&#xff1a; 切口工具槽口延伸戳记工具薄片和槽口中的切割法线 切口工具 您可以使用切口工具在空心或薄壁圆柱体和圆锥体中生成切口。通过选择圆柱面或圆锥面上的边线&#xff0c;您可以将零件平展为钣金。 在早期版本中&#xff0c;如果您有圆柱形或圆锥形…

CTF是什么?

前言 &#x1f4bb;随着大数据、人工智能的发展&#xff0c;人们步入了新的时代&#xff0c;逐渐走上科技的巅峰。 ⚔科技是一把双刃剑&#xff0c;网络安全不容忽视&#xff0c;人们的隐私在大数据面前暴露无遗&#xff0c;账户被盗、资金损失、网络诈骗、隐私泄露&#xff…

spring源码环境搭建

spring源码环境搭建 步骤1 &#xff1a;下载Spring-framework源码 https://github.com/spring-projects/spring-framework/tree/5.1.x步骤2&#xff1a;修改build.gradle配置文件 修改repositories里面的maven使用阿里云镜像 maven { url “https://maven.aliyun.com/reposit…

JVM基础知识(内存区域划分,类加载,GC垃圾回收)

目录 内存区域划分 JVM中的栈 JVM中的堆 程序计数器 方法区(元数据区) 给一段代码,某个变量在哪个区域上? 类加载 类加载时机 双亲委派模型 GC 垃圾回收机制 GC 实际工作过程 1.找到垃圾/判定垃圾 1.可达性分析(Java中的做法) 2.引用计数 2.清理垃圾 1.标记清除…

小程序商城开发搭建;

小程序商城系统是基于移动互联网的一种在线购物平台&#xff0c;提供线上商城购物、在线下单、支付及配送等功能。随着智能手机普及率的加速提升&#xff0c;小程序商城系统也成为更多商家的选择。下面是小程序商城系统的主要功能介绍&#xff1a; 1、商品展示&#xff1a;商家…

Vue路由与node.js环境搭建

目录 前言 一.Vue路由 1.什么是spa 1.1简介 1.2 spa的特点 1.3 spa的优势以及未来的挑战 2.路由的使用 2.1 导入JS依赖 2.2 定义两个组件 2.3 定义组件与路径对应关系 2.4 通过路由关系获取路由对象 2.5 将对象挂载到vue实例中 2.6 定义触发路由事件的按钮 2.7 定…

华为云云耀云服务器L实例评测|云耀云服务器L实例的购买及使用体验

华为云云耀云服务器L实例评测&#xff5c;云耀云服务器L实例的购买及使用体验 一、云耀云服务器L实例介绍1.1 云耀云服务器L实例简介1.2 云耀云服务器L实例特点1.3 云耀云服务器L实例使用场景 二、云耀云服务器L实例支持的镜像2.1 镜像类型2.2 系统镜像2.3 应用镜像 三、购买云…

HOOPS Visualize 2023 SP2 U1 Crack-HOOPS Visualize

HOOPS Visualize 是一个以工程为中心的高性能图形库&#xff0c;用于在桌面、移动和 AR/VR 设备上渲染 3D CAD 模型。该 3D 图形库具有线程安全的 C 和 C# 接口以及 OpenGL 和 DirectX 驱动程序&#xff0c;并由响应迅速的专业图形专家提供支持。通过访问最新的 3D GPU 功能&am…

【业务功能篇112】Springboot + Spring Security 权限管理-登录模块开发实战

合家云社区物业管理平台 4.权限管理模块研发 4.3 登录模块开发 前台和后台的认证授权统一都使用SpringSecurity安全框架来实现。首次登录过程如下图: 4.3.1 生成图片校验码 4.3.1.1 导入工具类 (1) 导入Constants 常量类 /*** 通用常量类* author spikeCong* date 2023/5…