feat: 集成音频播放组件和视频播放器

This commit is contained in:
2026-02-11 14:49:16 +08:00
parent 9a92e6ffb4
commit c6feeeef8b
48 changed files with 15614 additions and 1584 deletions

View File

@@ -1,295 +0,0 @@
<template>
<view>
<u-popup key="1" :show="videoShow" :round="10" @close="closeVideo">
<view class="" style="padding: 10px;">
<view>
<view class="container">
<div
ref="videoContent"
@tap="renderScript.handleClick"
id="url-player-test"
:videoData="videoData"
:opname="opname"
:change:opname="renderScript.opnameChange"
:change:videoData="renderScript.receiveMsg"
></div>
</view>
</view>
<div class="fullScreenButton-container">
<div
:class="`prism-fullscreen-btn ${isFullScreen ? 'fullscreen' : ''}`"
@tap="renderScript.changeVideoScreen"
></div>
</div>
<view class="btn" style="text-align: center;">
<button type="primary" @click="closeVideo" size="mini">关闭视频</button>
</view>
</view>
</u-popup>
</view>
</template>
<script setup lang="ts">
import { ref, nextTick } from 'vue'
import type { IVideoData } from '@/types/video'
// Props 定义
interface Props {
videoData: IVideoData
}
const props = defineProps<Props>()
// Emits 定义
const emit = defineEmits<{
close: []
}>()
// 响应式数据
const videoShow = ref(true)
const isFullScreen = ref(false)
const opname = ref('')
// 方法: 关闭视频
const closeVideo = () => {
opname.value = 'close'
nextTick(() => {
emit('close')
})
}
</script>
<script module="renderScript" lang="renderjs">
// RenderJS 模块 - 保持 Vue2 写法
// jQuery 在 RenderJS 中通过全局变量访问
var $ = window.jQuery || window.$
export default {
mounted() {
console.log(this.options, '这是monted')
},
data() {
return {
player: null,
curTime: null,
curStatus: null
}
},
watch: {
curTime(val) {
if (this.curTime !== null && this.curStatus !== null) {
// 可以添加逻辑
}
}
},
methods: {
handleClick(event, ownerInstance) {
console.log('event at line 165:', event)
},
emitData(event, ownerInstance) {
ownerInstance.callMethod('recordTime', {
time: this.curTime,
status: this.curStatus
})
},
changeVideoScreen(event, ownerInstance) {
var status = this.player.fullscreenService.getIsFullScreen()
ownerInstance.callMethod('screenChange', {
status: status,
primary: status ? 'portrait' : 'landscape'
})
if (status) {
setTimeout(() => {
plus.screen.lockOrientation('portrait-primary')
this.player.fullscreenService.cancelFullScreen()
}, 100)
} else {
this.player.fullscreenService.requestFullScreen()
setTimeout(() => {
plus.screen.lockOrientation('landscape-primary')
}, 100)
}
},
endEmitData(event, ownerInstance) {
ownerInstance.callMethod('handleEnd')
},
getLive() {
if (this.videoData.type == 1) {
var fullScreenButtonComponent = Aliplayer.Component({
init: function(status, toAddress) {
this.fullScreenStatus = status
this.$html = $('.fullScreenButton-container')
},
createEl: function(el) {
this.$html.find('.ad').attr('src', this.adAddress)
var $adWrapper = this.$html.find('.ad-wrapper')
$adWrapper.attr('href', this.toAddress)
$adWrapper.click(function() {})
$(el).find('.prism-time-display').after(this.$html)
},
playing: function(player, e) {
this.$html.show()
}
})
console.log('this.currentVideoList at line 456111111111111111111111:', this.videoList)
var player = new Aliplayer({
id: 'url-player-test',
vid: this.videoData.videoId,
playauth: this.videoData.playAuth,
encryptType: 1,
playConfig: {
EncryptType: 'AliyunVoDEncryption'
},
width: '100%',
height: '200px',
playsinline: true,
controlBarVisibility: 'click',
cover: '',
components: [
{
name: 'adComponent',
type: fullScreenButtonComponent,
args: ['http://101.201.146.165:8088/Pf-EH/statics/uploadFile/2024-05-10/b0f420c7-9178-41ad-9dd6-f59a64a6e190.png']
}
],
skinLayout: [
{ name: 'bigPlayButton', align: 'blabs', x: 30, y: 80 },
{ name: 'H5Loading', align: 'cc' },
{ name: 'errorDisplay', align: 'tlabs', x: 0, y: 0 },
{ name: 'infoDisplay' },
{ name: 'tooltip', align: 'blabs', x: 0, y: 56 },
{ name: 'thumbnail' },
{
name: 'controlBar',
align: 'blabs',
x: 0,
y: 0,
children: [
{ name: 'progress', align: 'blabs', x: 0, y: 44 },
{ name: 'playButton', align: 'tl', x: 15, y: 12 },
{ name: 'timeDisplay', align: 'tl', x: 10, y: 7 },
{ name: 'prism-speed-selector', align: 'tr', x: 15, y: 12 },
{ name: 'volume', align: 'tr', x: 5, y: 10 }
]
}
]
}, function(player) {})
this.player = player
}
},
opnameChange(newValue, oldValue, ownerVm, vm) {
console.log('opnameChange-----------', newValue)
if (newValue == 'close') {
if (this.player) {
this.player.dispose()
}
}
},
receiveMsg(newValue, oldValue, ownerVm, vm) {
console.log('数据变化newValue', newValue)
if (newValue.playAuth) {
this.loadWebPlayerSDK()
}
},
checkValue() {
console.log(this.videoData, this.videoData.playAuth, '1111888888')
if (!this.videoData.playAuth) {
setTimeout(() => {
this.checkValue()
}, 1000)
} else {
console.log('this.videoList at line 这是这只只是594:', this.currentVideoList)
this.getLive()
}
},
loadWebPlayerSDK() {
return new Promise((resolve, reject) => {
// 先加载 jQuery
if (!window.jQuery && !window.$) {
const jquery_tag = document.createElement('script')
jquery_tag.type = 'text/javascript'
jquery_tag.src = 'https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js'
jquery_tag.charset = 'utf-8'
jquery_tag.onload = () => {
$ = window.jQuery || window.$
this.loadAliPlayerSDK(resolve, reject)
}
jquery_tag.onerror = () => {
console.error('jQuery 加载失败')
reject(new Error('jQuery 加载失败'))
}
document.body.appendChild(jquery_tag)
} else {
$ = window.jQuery || window.$
this.loadAliPlayerSDK(resolve, reject)
}
})
},
loadAliPlayerSDK(resolve, reject) {
const s_tag = document.createElement('script')
s_tag.type = 'text/javascript'
s_tag.src = 'https://g.alicdn.com/apsara-media-box/imp-web-player/2.20.3/aliplayer-min.js'
s_tag.charset = 'utf-8'
s_tag.onload = () => {
const s_tag1 = document.createElement('script')
s_tag1.type = 'text/javascript'
s_tag1.src = 'https://player.alicdn.com/aliplayer/presentation/js/aliplayercomponents.min.js'
s_tag1.charset = 'utf-8'
s_tag1.onload = () => {
this.checkValue()
resolve()
}
s_tag1.onerror = () => {
console.error('阿里云播放器组件加载失败')
reject(new Error('阿里云播放器组件加载失败'))
}
document.body.appendChild(s_tag1)
}
s_tag.onerror = () => {
console.error('阿里云播放器 SDK 加载失败')
reject(new Error('阿里云播放器 SDK 加载失败'))
}
document.body.appendChild(s_tag)
const l_tag = document.createElement('link')
l_tag.rel = 'stylesheet'
l_tag.href = 'https://g.alicdn.com/apsara-media-box/imp-web-player/2.20.3/skins/default/aliplayer-min.css'
document.body.appendChild(l_tag)
}
}
}
</script>
<style scoped>
.fullScreenButton-container {
color: #fff;
float: right;
height: 35px;
margin-top: 6px;
margin-right: 5px;
display: flex;
align-items: center;
position: relative;
}
</style>

View File

@@ -1,123 +0,0 @@
<template>
<view class="richDetail">
<view
scroll-x="true"
class="detail_title video_box"
style="background-color: #fff"
>
<view
v-for="(v, i) in dataList"
:key="v.id"
:class="`video_item ${currentVideo && currentVideo.id == v.id ? 'hot' : ''}`"
@click="handleClick(v, i)"
>
{{ v.type == '2' ? '音频' : '视频' }}{{ getNumber(i + 1) }}
</view>
</view>
<slot name="richHeadImg"></slot>
</view>
</template>
<script setup lang="ts">
import type { IVideoInfo, IChapterDetail } from '@/types/video'
// Props 定义
interface Props {
detailInfo: IChapterDetail
dataList: IVideoInfo[]
currentVideo: IVideoInfo | null
changeVideoLock: boolean
}
const props = defineProps<Props>()
// Emits 定义
const emit = defineEmits<{
open: [video: IVideoInfo]
}>()
// 方法: 格式化序号为两位数
const getNumber = (num: number): string => {
if (num >= 10) {
return num.toString()
} else {
return `0${num}`
}
}
// 方法: 处理视频点击
const handleClick = (data: IVideoInfo, index: number) => {
if (props.changeVideoLock) {
return
}
console.log('data at line 35:', data)
emit('open', data)
}
</script>
<style lang="scss" scoped>
.commonPageBox {
padding: 40rpx 0;
}
.contentBox {
.headImage {
margin-bottom: 20rpx;
}
.detail_title {
padding: 0 20rpx 0;
font-size: 26rpx;
line-height: 65rpx;
font-weight: bold;
text-align: center;
box-sizing: border-box;
margin-bottom: 20rpx;
overflow: hidden;
}
.rich_box {
padding: 20rpx;
box-sizing: border-box;
p {
display: block;
text-indent: 2em;
letter-spacing: 2px !important;
line-height: 46rpx;
}
}
}
.richDetail {
width: 100%;
height: 100%;
}
.video_box {
width: 100%;
.video_item {
width: 23%;
margin-right: 10rpx;
margin-bottom: 20rpx;
float: left;
border: 2rpx solid #2979ff;
background: #fff;
color: #2979ff;
text-align: center;
border-radius: 10rpx;
box-shadow: 0px 0px 6rpx 0px rgba(255, 255, 255, 1);
}
.video_item:nth-child(4n) {
margin-right: 0;
}
}
.hot {
background-color: #2979ff !important;
color: #fff !important;
}
</style>

View File

@@ -0,0 +1,105 @@
<template>
<div class="video-player">
<image :src="coverImageUrl" class="video-cover" style="width: 100%; height:100%;" />
<CxAudioPlayer
v-if="list.length > 0"
:list="list"
:autoplays="true"
style="
display: flex; align-items: center; justify-content: center;
position: absolute; left: 0; top: 0;
width: 100%; height: 100%;
background-color: rgba(0, 0, 0, 0.6);
"
/>
</div>
</template>
<script>
import { mainClient } from '@/api/clients';
import CxAudioPlayer from './cx-audio-play/cx-audio-play.vue'
export default {
props: {
currentVideo: {
type: Object,
default: () => {}
},
coverImageUrl: {
type: String,
default: ''
},
http: {
type: Object,
default: () => {}
},
},
components: {
CxAudioPlayer
},
watch: {
currentVideo: {
handler(newVal, oldVal) {
if (!newVal || !newVal.id) return
this.fetchRealAudioUrl(newVal)
},
immediate: true,
deep: true,
}
},
data() {
return {
isfresh: false,
screenLoading: false,
isFullScreen: false,
changeVideoLock: false,
secondCountDown: 10,
list: []
}
},
methods: {
async fetchRealAudioUrl(videoInfo) {
if (!videoInfo) return
const data = { ...videoInfo }
try {
const res = await mainClient.request({
url: 'sociology/course/checkVideo',
method: 'POST',
data,
header: {
'Content-Type': 'application/json'
}
})
console.log('获取播放凭证666',JSON.stringify(res.video));
const real = res && res.video ? res.video : null
if (!real) {
this.list = []
return
}
const src = real.videoUrl || real.m3u8Url || real.source || ''
if (!src) {
this.list = []
return
}
this.list = [{ recorPath: src }]
} catch (e) {
this.list = []
}
}
}
}
</script>
<style scoped>
.video-player {
position: relative;
height: 400rpx;
width: 100%;
.player {
display: flex;
align-items: center;
justify-content: center;
position: absolute; left: 0; top: 0; width: 100%; height: 100%;
background-color: rgba(0, 0, 0, 0.7);
}
}
</style>

View File

@@ -0,0 +1,16 @@
## 2.0.12023-12-15
优化体积和倍数播放功能
## 2.0.02023-12-15
修改一些bug兼容基本平台
## 1.0.72023-12-15
优化功能体积速度
## 1.0.52023-12-15
优化功能,兼容基本平台
## 1.0.42023-12-15
简化代码优化功能处理一些bug
## 1.0.32023-02-09
修改切换的某些bug新增自动播放下一首功能
## 1.0.22022-12-16
适配app平台
## 1.0.12022-12-16
1.0.1

View File

@@ -0,0 +1,585 @@
<template>
<!--音频组件-->
<view>
<view class="bgfff">
<view>
<view class="audo-video">
<!--音频api处[视频代替音频-实现倍数功能]-->
<video
id="myVideo" ref="myVideo" :src="recorPath" class="hidden" @timeupdate="timeupdate"
:autoplay="autoplays" @loadedmetadata="loadedmetadata" @ended="next" :controls="true"
:show-center-play-btn="false" :show-mute-btn="true"
/>
<!--音频api处[视频代替音频-实现倍数功能]-->
<!--音频播放按钮处-->
<view class="audo-top">
<!--上一首切换按钮-->
<!-- <image v-if="jian" style="width:50rpx;height:50rpx;" @click="nosig" src="./static/sys.png" mode="aspectFill"></image>
<image v-else @click="sig" src="./static/xys.png" style="width:50rpx;height:50rpx;transform:rotate(180deg)"
mode="aspectFill"></image> -->
<!--上一首切换按钮-->
<!--快退按钮-->
<image src="./static/kt.png" style="width:60rpx;height:60rpx;" mode="aspectFill" @click="kt()"></image>
<!--快退按钮-->
<!--播放按钮-->
<image v-if="succes" src="./static/bofang2.png" mode="aspectFill"
style="width:180rpx;height:180rpx;" @click="plays()"></image>
<image v-else src="./static/zt.png" mode="aspectFill"
style="width:180rpx;height:180rpx;" @click="plays()"></image>
<!--播放按钮-->
<!--快进按钮-->
<image src="./static/kj.png" style="width:60rpx;height:60rpx;" mode="aspectFill" @click="kj()"></image>
<!--快进按钮-->
<!--下一首切换按钮-->
<!-- <image v-if="jia" @click="noxig" style="width:50rpx;height:50rpx;transform:rotate(180deg)" src="./static/sys.png"
mode="aspectFill"> </image>
<image v-else style="width:50rpx;height:50rpx;" src="./static/xys.png" @click="xig" mode="aspectFill"></image> -->
<!--下一首切换按钮-->
</view>
<!--音频播放按钮处-->
<view class="audo-a" style="margin:0 auto;">
<!--进度条-->
<view class="slider-box">
<text class="mm">{{timer}}</text>
<slider style="width: 370rpx;" @change="sliderChange" @changing="sliderChanging"
class="audio-slider" block-size="16" :min="0" :max="duration" :value="currentTime"
activeColor="#FFA929" />
<text class="ss" v-if="overTimer!='NaN:NaN'">{{overTimer}}</text>
<text class="ss" v-else>00.00</text>
</view>
<!--进度条-->
<!--倍速-->
<view class="beishu" style="border:3rpx solid #C8C9CC;" @click="beishu">{{BsNav[bsindex].bs}} X
</view>
<!--倍速-->
</view>
</view>
</view>
</view>
<view class="h-100"></view>
<!--占位-->
</view>
<!--音频组件 Author:chenxin-->
</template>
<script>
/*
list -- 音频文件传入 不传无法播放/数组形式
Faskms -- 快进秒数 number 默认15秒
Slowms -- 快退秒数 number 默认15秒
autoNext -- 是否自动播放下一首
autoplays -- 进入页面是否自动播放 - 默认false
slideYes -- 滑动进度条时是否开启播放 - 默认false
switAud -- 切换上下音频是否开启播放 - 默认false
BsNav -- 倍数数据传入/数组形式
按钮图片未自定义,如想改动请在组件内部修改,页面头部已注释 -- 逻辑根据自己需求改
目前只测试 微信小程序和H5和APP -- 其他平台未知
Author:chenxin 交流vx:cxalq8-24
*/
export default {
name: "cx-audio-play",
props: {
list: { //音频数据
Type: Array,
default: () => []
},
Faskms: { //快进秒数
Type: Number,
default: 15,
},
Slowms: { //快退秒数
Type: Number,
default: 15,
},
autoNext: {
Type: Boolean,
default: false,
},
autoplays: { //是否开启自动播放
Type: Boolean,
default: false,
},
slideYes: { //滑动进度条 - 是否开启播放
Type: Boolean,
default: false,
},
switAud: {
Type: Boolean, //切换上下音频 - 是否开启播放
default: false,
},
BsNav: { //倍数-传入
Type: Array,
default: () => [{
id: 0.5,
bs: '0.5',
}, {
id: 0.8,
bs: '0.8'
}, {
id: 1.0,
bs: '1.0'
}, {
id: 1.25,
bs: '1.25'
}, {
id: 1.5,
bs: '1.5'
}],
},
},
data() {
return {
jian: true, //减-切换图标
jia: true, //加-切换图标
succes: false, //播放按钮
bsid: '', //倍数默认显示第一个
bsindex: 0, //倍数默认显示第一个
num: 0,
current: 0, //当前选中的索引
recorPath: '', //音频播放地址
lock: false, // 锁
currentTime: 0, //当前进度
duration: 100, // 总进度
videoContext: null,
loading: true, //锁 加载
}
},
onReady() {},
onShow() {},
mounted() {
this.videoContext = uni.createVideoContext('myVideo', this)
//默认播放第一个 -- 按钮展示
if (this.list.length != 0) {
this.recorPath = this.list[0].recorPath
if (this.list.length > 1) { //音频文件大于1 -- 下一个切换默认显示
this.jia = false
}
if (this.autoplays) {
this.succes = true
}
}
//倍数默认处理
if (this.BsNav.length != 0) {
const defaultRate = 1.0
const index = this.BsNav.findIndex(item => item.id === defaultRate)
if (index !== -1) {
this.bsid = this.BsNav[index].id
this.bsindex = index
} else {
this.bsid = this.BsNav[0].id
this.bsindex = 0
}
this.$nextTick(() => {
//#ifdef H5
this.$refs.myVideo.playbackRate(this.bsid)
//#endif
//#ifndef H5
this.videoContext.playbackRate(this.bsid)
//#endif
})
}
},
updated() {
},
onLoad() {
},
onHide() { //监听页面离开 - 销毁音频
//#ifdef H5
this.$refs.myVideo.stop();
//#endif
//#ifndef H5
this.videoContext.stop();
//#endif
},
onUnload() { //监听页面卸载 - 销毁音频
//#ifdef H5
this.$refs.myVideo.stop();
//#endif
//#ifndef H5
this.videoContext.stop();
//#endif
},
destroyed() {
// this.innerAudioContext.stop();
},
computed: {
timer() {
return calcTimer(this.currentTime)
},
overTimer() {
return calcTimer(this.duration)
}
},
watch: { },
methods: {
plays() { //播放暂停
if (!this.list || this.list.length == 0) {
console.log('暂无音频数据~')
return;
}
this.playloading()
this.succes = !this.succes
if (this.succes) {
// this.currentTime = 0
// console.log('-----------------')
//#ifdef H5
this.$refs.myVideo.play()
//#endif
//#ifndef H5
this.videoContext.play()
//#endif
} else {
uni.hideLoading()
//#ifdef H5
this.$refs.myVideo.pause()
//#endif
//#ifndef H5
this.videoContext.pause()
//#endif
}
},
beishu() {
if (!this.BsNav || this.BsNav.length === 0) {
return
}
let nextIndex = this.bsindex + 1
if (nextIndex >= this.BsNav.length) {
nextIndex = 0
}
const item = this.BsNav[nextIndex]
this.bsid = item.id
this.bsindex = nextIndex
//#ifdef H5
this.$refs.myVideo.playbackRate(item.id)
//#endif
//#ifndef H5
this.videoContext.playbackRate(item.id)
//#endif
},
// 更新进度条
timeupdate(event) {
if (this.lock) return; // 锁
var currentTime, duration;
if (event.detail.detail) {
currentTime = event.detail.detail.currentTime
duration = event.detail.detail.duration
} else {
currentTime = event.detail.currentTime
duration = event.detail.duration
}
this.currentTime = currentTime
this.duration = duration
},
// 拖动进度条
sliderChange(data) {
const value = data.detail.value
//此处滑动进度条--开始播放
if (this.slideYes && !this.succes) {
//#ifdef H5
this.$refs.myVideo.play()
//#endif
//#ifndef H5
this.videoContext.play()
//#endif
this.succes = true
}
//#ifdef H5
this.$refs.myVideo.seek(value) //获取秒数
//#endif
//#ifndef H5
this.videoContext.seek(value) //获取秒数
//#endif
this.currentTime = value
this.lock = false
},
//拖动中
sliderChanging(data) {
this.lock = true
if (data.detail.value == 0) {
this.succes = false
//#ifdef H5
this.$refs.myVideo.pause()
//#endif
//#ifndef H5
this.videoContext.pause()
//#endif
}
this.currentTime = data.detail.value
},
// 视频加载完成
loadedmetadata(data) {
this.duration = data.detail.duration
},
sig() { //上一首
if (!this.list || this.list.length == 0) {
console.log('暂无音频数据~')
return;
}
this.num -= 1
if (this.num < this.list.length) {
this.loading = true
this.playloading() //加载框
}
if (this.num + 1 < this.list.length && this.num + 1 != 1) { //点击上一首小于音频数据总长度
this.jia = false // 下按钮-亮且可点击
this.jian = false // 上按钮-亮且可点击
} else {
this.jian = true // 上按钮-灰且阻止
this.jia = false // 下按钮-亮且可点击
}
this.recorPath = this.list[this.num].recorPath
if (this.switAud) { //切换时是否默认开启播放
this.succes = true
setTimeout(() => {
//#ifdef H5
this.$refs.myVideo.play()
//#endif
//#ifndef H5
this.videoContext.play()
//#endif
}, 100)
} else {
this.succes = false
}
},
xig() { //下一首
if (!this.list || this.list.length == 0) {
console.log('暂无音频数据~')
return;
}
this.num += 1
if (this.num < this.list.length) {
this.loading = true
this.playloading() //加载框
}
if (this.num + 1 < this.list.length) { //点击下一首小于音频数据总长度
this.jia = false // 下按钮-亮且可点击
this.jian = false // 上按钮-亮且可点击
} else { //大于总长度
this.jia = true //下按钮 - 灰且阻止
this.jian = false //上按钮 - 亮可点击
}
this.recorPath = this.list[this.num].recorPath
if (this.switAud) { //切换时是否默认开启播放
this.succes = true
setTimeout(() => {
//#ifdef H5
this.$refs.myVideo.play()
//#endif
//#ifndef H5
this.videoContext.play()
//#endif
}, 100)
} else {
this.succes = false
}
},
nosig() {
uni.showToast({
title: '到头了~',
icon: "none"
})
},
noxig() {
uni.showToast({
title: '没有更多了~',
icon: "none"
})
},
kt() { //快退
if (!this.list || this.list.length == 0) {
console.log('暂无音频数据~')
return;
}
let a = (this.currentTime - Math.floor(15 % 60)).toFixed(0) //当前时间-15秒
if (a < 1) {
this.succes = false
//#ifdef H5
this.$refs.myVideo.pause()
//#endif
//#ifndef H5
this.videoContext.pause()
//#endif
}
//#ifdef H5
this.$refs.myVideo.seek(a)
//#endif
//#ifndef H5
this.videoContext.seek(a)
//#endif
},
kj() { //快进
if (!this.list || this.list.length == 0) {
console.log('暂无音频数据~')
return;
}
let a = (this.currentTime + Math.floor(15 % 60)).toFixed(0) //当前时间+15秒
//#ifdef H5
this.$refs.myVideo.seek(a)
//#endif
//#ifndef H5
this.videoContext.seek(a)
//#endif
},
next(data) { //监听音频结束
this.succes = false
/*音频结束--是否自动播放下一首*/
if (!this.autoNext) {
return
}
if (this.num + 1 < this.list.length) {
this.succes = true
this.num += 1
this.recorPath = this.list[this.num].recorPath
setTimeout(() => {
//#ifdef H5
this.$refs.myVideo.play()
//#endif
//#ifndef H5
this.videoContext.play()
//#endif
}, 100)
} else {
this.jia = true //下按钮 - 灰且阻止
this.jian = false //上按钮 - 亮可点击
}
// console.log('音频结束-------')
},
playloading() { //加载框--封
if (this.loading) {
uni.showLoading({
title: "音频缓存中..."
})
this.loading = false
}
setTimeout(() => {
uni.hideLoading()
}, 1600)
},
},
watch: {}
}
function calcTimer(timer) {
if (typeof timer !== 'number' || !isFinite(timer) || timer <= 0) {
return '00:00'
}
let mm = Math.floor(timer / 60)
let ss = Math.floor(timer % 60)
if (mm < 10) {
mm = '0' + mm
}
if (ss < 10) {
ss = '0' + ss
}
return mm + ':' + ss
}
</script>
<style lang="scss" scoped>
/* #video {
width: 100%;
} */
.audo-video {
padding-bottom: 20rpx;
color: #999;
}
.slider-box {
display: flex;
align-items: center;
justify-content: center;
font-size: 27rpx;
color: #999;
}
button {
display: inline-block;
width: 100rpx;
background-color: #fff;
font-size: 24rpx;
color: #000;
padding: 0;
}
.video {
width: 100%;
height: 400rpx;
top: 0;
left: 0;
position: absolute;
}
.hidden {
position: fixed;
top: 0;
left: -10rpx;
z-index: -1;
width: 1rpx;
height: 1rpx;
}
.audo-top {
padding: 20rpx 40rpx;
display: flex;
justify-content: space-around;
align-items: center;
position: relative;
image {
width: 45rpx;
height: 45rpx;
}
}
.audo-a {
display: flex;
justify-content: space-between;
align-items: center;
width: 700rpx;
position: relative;
z-index: 9;
}
.beishu {
position: relative;
width: 100rpx;
padding-top: 5rpx;
padding-bottom: 5rpx;
text-align: center;
border-radius: 25rpx;
font-size: 28rpx;
}
.absolute {
position: absolute;
.beishu-a {
width: 200rpx;
border-radius: 20rpx;
text-align: center;
line-height: 90rpx;
background: #fff;
.title {
padding-left: 30rpx;
}
}
}
</style>

View File

@@ -0,0 +1,85 @@
{
"id": "cx-audio-play",
"displayName": "音频播放组件,自定义修改",
"version": "2.0.1",
"description": "音频播放组件兼容微信小程序、h5等可倍数播放快进快退切换上下音频等",
"keywords": [
"音频",
"音频播放",
"播放器",
"倍数播放",
"播放"
],
"repository": "",
"engines": {
"HBuilderX": "^3.5.5"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "插件不采集任何数据",
"permissions": "无"
},
"npmurl": "",
"type": "component-vue"
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"Vue": {
"vue2": "y",
"vue3": "u"
},
"App": {
"app-vue": "y",
"app-nvue": "u"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u",
"钉钉": "u",
"快手": "u",
"飞书": "u",
"京东": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
}
}

View File

@@ -0,0 +1,13 @@
### 组件各参说明 :
____
#### 1. 实现切换上下首、自动播放、倍数播放、快进快退、进度条播放等
#### 2. list 【Array】 音频数据/不传无法播放
#### 3. Seconds 【number】 快进快退秒数 - 默认15秒
#### 4. autoNext 【Boolean】 自动播放下一首 - 默认不开启
#### 5. autoplays 【Boolean】 进入页面是否自动播放 - 默认不开启
#### 6. slideYes 【Boolean】 拖动进度条时开启播放 - 默认不开启
#### 7. switAud 【Boolean】 切换上下音频开启播放 - 默认开启
#### 8. BsNav 【Array】 倍数数据
#### 本音频组件扩展性强样式功能随意调整兼容H5微信小程序App建议下载示例项目避免因图片缺失引起报错谢谢支持~
#### 作者: chenxin ,微信交流: cxalq8-24
----

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff