Explorar el Código

init test

test
douzhuo hace 2 años
padre
commit
98b49c470e
Se han modificado 11 ficheros con 692 adiciones y 0 borrados
  1. +87
    -0
      components/yz-audio/audioBg.js
  2. +119
    -0
      components/yz-audio/index.scss
  3. BIN
      components/yz-audio/static/backimg.png
  4. BIN
      components/yz-audio/static/bg.png
  5. BIN
      components/yz-audio/static/bg_act.png
  6. BIN
      components/yz-audio/static/loading.png
  7. BIN
      components/yz-audio/static/loading2.png
  8. BIN
      components/yz-audio/static/pausebtn.png
  9. BIN
      components/yz-audio/static/playbtn.png
  10. +432
    -0
      components/yz-audio/yz-audio.vue
  11. +54
    -0
      store/index.js

+ 87
- 0
components/yz-audio/audioBg.js Ver fichero

@@ -0,0 +1,87 @@
import {
mapState,
mapActions,
mapMutations
} from 'vuex'
export const audios = {
data() {
return {
isBgPlay: false, // 是否禁止拖拽进度条
}
},

computed: {
...mapState(['bgAudioMannager']),
},

methods: {
setAudio(obj) {
this.bgAudioMannager.title = '录音音频';
this.bgAudioMannager.src = obj.src
this.bgAudioMannager.startTime = obj.currentTime
},

setAudioFunc() {
this.bgAudioMannager.onCanplay(() => {
console.log('可以播放');
});
this.bgAudioMannager.onStop(() => {
console.log('停止播放');
this.isBgPlay = false
});

this.bgAudioMannager.onPause(() => {
console.log('暂停播放');
this.isBgPlay = false
// 设置当前暂停的视频播放位置
// this.seek(this.bgAudioMannager.currentTime)
// this.play()
});
this.bgAudioMannager.onEnded(() => {
console.log('自然播放结束事件');
this.isBgPlay = false
});
this.bgAudioMannager.onError((res) => {
console.log(res.errMsg);
console.log(res.errCode);
});

this.bgAudioMannager.onTimeUpdate(() => {
this.isBgPlay = true
this.duration = this.bgAudioMannager.duration;
this.currentTime = this.bgAudioMannager.currentTime;
this.$emit('timeUpdate', {
duration: this.bgAudioMannager.duration,
currentTime: this.bgAudioMannager.currentTime
})
});
},
// 背景音频暂停
audioPause() {
this.bgAudioMannager.pause()
},
// 背景音频播放
audioPlay() {
this.pause()
this.bgAudioMannager.play()
},
//背景音频指定秒数播放
audioSeek(t) {
this.bgAudioMannager.seek(t)
},
// 停止背景音频播放
stopAduio() {
console.log(this.bgAudioMannager)
this.bgAudioMannager.pause()
if (this.bgAudioMannager && this.bgAudioMannager.src) {
this.bgAudioMannager.src = ''
}
}
}
}

+ 119
- 0
components/yz-audio/index.scss Ver fichero

@@ -0,0 +1,119 @@
@mixin textoverflow() {
display: -webkit-box;
overflow: hidden;
text-overflow: ellipsis;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
@keyframes rowup {
0% {
-webkit-transform: translate(-50%, -50%) rotate(0deg);
transform-origin: center center;
}

100% {
-webkit-transform: translate(-50%, -50%) rotate(360deg);
transform-origin: center center;
}
}
.imt-audio{
position:relative;
width: 100%;
display: flex;
box-sizing: border-box;
background: #fff;
overflow: hidden;
.top {
width: 140rpx;
position: relative;
}

.audio-wrapper {
display: flex;
flex-direction: column;
flex: 1;
color: #fff;
margin-left: 20rpx;
}
.slidebox {
display: flex;
justify-content: space-between;
width: 96%;
}
/deep/ .uni-slider-tap-area {
padding: 0;
}
/deep/ .uni-slider-wrapper {
min-height: 0;
}
/deep/ .uni-slider-handle-wrapper {
height: 6px;
}
.audio-slider {
padding-top: 10rpx;
margin-left: 150rpx;
position: absolute;
bottom: 40rpx;
width: 75vw;
left: 0;
padding: 0;
}

// .cover {
// width: 120rpx;
// height: 120rpx;
// box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.2);
// position: absolute;
// top: 50%;
// left: 50%;
// transform: translate(-50%, -50%);
// animation-fill-mode: forwards;
// -webkit-animation-fill-mode: forwards;
// }

.play {
width: 48rpx;
height: 48rpx;
z-index: 99;
background: rgba(0, 0, 0, 0.4);
border-radius: 50%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
&.loading{
width: 48rpx;
height: 48rpx;
animation: rotating_theme3 2s linear infinite;
}
}
}

@keyframes rotating {
0% {
transform: rotateZ(0deg)
}
100% {
transform: rotateZ(360deg)
}
}
@keyframes rotating_theme3 {
0% {
transform: translate(-50%, -50%) rotateZ(0deg)
}
100% {
transform: translate(-50%, -50%) rotateZ(360deg)
}
}

.hItem
{
margin-left: 16rpx;
}

.extrButton
{
font-size: 36rpx;
}

BIN
components/yz-audio/static/backimg.png Ver fichero

Antes Después
Anchura: 64  |  Altura: 16  |  Tamaño: 594 B

BIN
components/yz-audio/static/bg.png Ver fichero

Antes Después
Anchura: 64  |  Altura: 64  |  Tamaño: 1.8 KiB

BIN
components/yz-audio/static/bg_act.png Ver fichero

Antes Después
Anchura: 64  |  Altura: 64  |  Tamaño: 1.9 KiB

BIN
components/yz-audio/static/loading.png Ver fichero

Antes Después
Anchura: 48  |  Altura: 48  |  Tamaño: 331 B

BIN
components/yz-audio/static/loading2.png Ver fichero

Antes Después
Anchura: 48  |  Altura: 48  |  Tamaño: 333 B

BIN
components/yz-audio/static/pausebtn.png Ver fichero

Antes Después
Anchura: 130  |  Altura: 123  |  Tamaño: 189 B

BIN
components/yz-audio/static/playbtn.png Ver fichero

Antes Después
Anchura: 130  |  Altura: 130  |  Tamaño: 274 B

+ 432
- 0
components/yz-audio/yz-audio.vue Ver fichero

@@ -0,0 +1,432 @@
<template>
<view class="imt-audio">
<template>
<view class="top">
<view class="audio-control-wrapper">
<image :src="require('./static/loading.png')" v-if="playState=='loading'" class="play loading">
</image>
<template v-else>
<image :src="require('./static/playbtn.png')" alt="play" @click="play" class="play"
v-if="playState=='pause'"></image>
<image :src="require('./static/pausebtn.png')" alt="pause" @click="pause" class="play" v-else>
</image>
</template>
</view>
</view>
<view class="audio-wrapper">
<view class="audio-flex">
<text>
{{formatSeconds(currentTime)}}
</text>
<slider class="audio-slider" block-size="12" :max="duration" :value="currentTime"
@change="sliderChange" @changing="sliderChanging"></slider>
<text>
{{formatSeconds(duration)}}
</text>
</view>

<view class="slidebox" @click="showTip">
<slot name="extraCtrls">
<image class="slide-img" :src="require('./static/backimg.png')" mode=""></image>
</slot>
</view>
<!-- 后台播放按钮区域 -->
<view class="popup" v-if="show" :class="{close: closeing}" @click="checkPlayer">
<template v-if="!isBgPlay">
<image :src="require('./static/bg.png')" mode=""></image>
</template>
<template v-else>
<image :src="require('./static/bg_act.png')" mode=""></image>
</template>
<text :class="{'act-test': isBgPlay}">后台播放</text>
</view>
</view>
<!--video在ios中不能完全隐藏,否则无法播放-->
<video id="videoPlayer" :autoplay="true" class="videoPlayer" :src="src" :muted="false"
style="width: 10rpx;height:10rpx;" @play="playerOnPlay" @pause="playerOnPause" @ended="playerOnEnded"
@timeupdate="playerOnTimeupdate" @waiting="playerOnWaiting" @error="playerOnError"></video>
</template>
</view>
</template>

<script>
/*
createInnerAudioContext()是audio组件的内部实现,不能熄屏播放、不能后台播放、不能倍速播放。
getBackgroundAudioManager() 可以熄屏播放、后台播放,不能倍速播放。缺点是响应速度很慢,无法实现精细、及时的进度控制,而且可能被别的程序占用。
因此这里只能用video来实现,video能倍速播放,不能熄屏播放、不能后台播放。而且避免了用createInnerAudioContext()实现的跳转到别的页面,还在播放的问题
因此应用程序可以在需要后台播放的时候(需要用户操作触发),再暂停这个控件的播放,然后自己用getBackgroundAudioManager实现后台播放
*/

import Vue from 'vue';
import {
mapMutations
} from 'vuex'
import {
audios
} from './audioBg.js'
export default {
mixins: [audios],
props: {
nowFileTime: {
type: [String, Number],
default: 0
},
},

watch: {
nowFileTime(oValue, nValue) {
this.duration = nValue
}
},

data() {
return {
src: '', //
poster: "",
name: "...",
singer: "...",
duration: 0,
currentTime: 0,
playState: "pause", //"loading"/"playing"/"pause"
isSliderChanging: false,
isFirst: false, // 是否阻止第一次赋值
audio: null, // 音频对象
show: false, // 控制展示用的
closeing: false, // 默认关闭
};
},
created() {
// 自定义组件,需要传递第二个参数为this,否则后续的pause等操作不起作用
this.videoCtx = uni.createVideoContext("videoPlayer", this);
this.audio = uni.createInnerAudioContext();
this.audio.autoplay = false;
this.createAudio()
this.setAudioFunc()
},

mounted() {
this.audio.onCanplay((e) => {
if (this.audio.duration != 0) {
this.playState = "pause"
this.$forceUpdate()
}
})
},

methods: {
...mapMutations(['createAudio', 'stopAduio']),
setSrc(value) {
console.log(this, ' 我打印this')
this.src = value;
console.log(this.src, '我在这儿里更换src')
// 获取当前音频的总时长
this.audio.src = value;
},

setPoster(value) {
this.poster = value;
},
setName(value) {
this.name = value;
},
setSinger(value) {
this.singer = value;
},

playerOnPlay(e) {
this.playState = "playing";
console.log('playerOnPlay', e)
this.$emit("play");
},
playerOnPause(e) {
this.playState = "pause";
console.log('playerOnPause', e)
this.$emit("pause");
},
playerOnEnded(e) {
this.playState = "pause";
console.log('playerOnEnded', e)
this.$emit("ended");
},

playerOnTimeupdate(e) {
if (this.isFirst) this.playState = "playing";
this.isFirst = true
this.duration = e.detail.duration;
this.currentTime = e.detail.currentTime;
this.$emit("timeUpdate", e.detail);
},

playerOnWaiting(e) {
this.playState = "loading";
console.log('playerOnWaiting', e)
},
playerOnError(e) {
console.log('playerOnError', e)
this.playState = "pause";
this.$emit("error", e);
},
formatSeconds(seconds) {
var result = typeof seconds === "string" ? parseFloat(seconds) : seconds;
if (isNaN(result)) return "";
let h = Math.floor(result / 3600) < 10 ?
"0" + Math.floor(result / 3600) :
Math.floor(result / 3600);
let m = Math.floor((result / 60) % 60) < 10 ?
"0" + Math.floor((result / 60) % 60) :
Math.floor((result / 60) % 60) + h * 60;
let s = Math.floor(result % 60) < 10 ?
"0" + Math.floor(result % 60) :
Math.floor(result % 60);
return `${h}:${m}:${s}`;
},
stop() {
this.videoCtx.stop();
},
seek(t) {
this.videoCtx.seek(t);
},
play() {
// if (this.videoCtx.currentTime != this.videoCtx.currentTime) {
// this.seek(this.currentTime)
// }
console.log('触发方法play')
this.videoCtx.play(); //在有的H5浏览器里,如果play不是用户触发的,则play()会报错
// 暂停后台播放
this.stopAduio()
},
pause() {
console.log('触发方法pause')
this.videoCtx.pause();
},
playbackRate(value) {
this.videoCtx.playbackRate(value);
//playbackRate不能在play之前或者之后立即调用,否则只有很少几率会成功
},
sliderChange(e) {
this.isSliderChanging = false;
//要通过e.detail.value获取,否则如果通过dom去读取slider的value
//就会存在滚动条拖不动的情况
// this.videoCtx.seek(e.detail.value);
let type = 'audio'
if (this.bgAudioMannager.paused === false) {
type = 'bgAudio'
}
this.$emit('sliderChangeComplate', { ...e, isType: type })
},
sliderChanging(e) {
this.isSliderChanging = true;
console.log(e, '当前正在改变')
},
// 关闭后台播放按钮
closeTip() {
this.closeing = false
setTimeout(() => {
this.show = false
}, 250)
},
// 展示后台播放按钮
showTip() {
this.show = true
setTimeout(() => {
this.closeing = true
}, 50)
},

// 点击后台播放音频事件
backAudio() {
this.pause()
let obj = {
src: this.src,
currentTime: this.currentTime
}
this.setAudio(obj)
},

// 切换播放源
checkPlayer() {
this.closeTip()
if (this.bgAudioMannager.paused === false) {
this.stopAduio()
} else {
this.backAudio()
}
}
},
}
</script>

<style lang="scss">
// @import './index.scss';
@mixin textoverflow() {
display: -webkit-box;
overflow: hidden;
text-overflow: ellipsis;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}

@keyframes rowup {
0% {
-webkit-transform: translate(-50%, -50%) rotate(0deg);
transform-origin: center center;
}

100% {
-webkit-transform: translate(-50%, -50%) rotate(360deg);
transform-origin: center center;
}
}

.imt-audio {
position: relative;
width: 100%;
height: 81rpx;
display: flex;
box-sizing: border-box;
background: #fff;

.top {
position: relative;
width: 100rpx;
}

.audio-wrapper {
position: relative;
padding: 0 20rpx;
display: flex;
flex: 1;
color: #fff;
.popup {
position: absolute;
right: 32rpx;
top: -122rpx;
z-index: 100;
width: 136rpx;
height: 122rpx;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
background: #fff;
border: 1rpx solid #E0E0E0;
transition: all 0.25s linear;
opacity: 0;
image {
width: 32rpx;
height: 32rpx;
}
text {
margin-top: 10rpx;
color: #333;
font-size: 24rpx;
}
.act-test {
color: #2671E2;
}
}
.close {
opacity: 1;
}
}

.slidebox {
flex-shrink: 0;
display: flex;
align-items: center;
.slide-img {
width: 32rpx;
height: 8rpx;
}
}

/deep/ .uni-slider-tap-area {
padding: 0;
}

/deep/ .uni-slider-wrapper {
min-height: 0;
}

/deep/ .uni-slider-handle-wrapper {
height: 6px;
}

.audio-slider {
flex-grow: 1;
}

.play {
width: 48rpx;
height: 48rpx;
z-index: 99;
background: rgba(0, 0, 0, 0.4);
border-radius: 50%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);

&.loading {
width: 48rpx;
height: 48rpx;
animation: rotating_theme3 2s linear infinite;
}
}
}

.audio-flex {
padding: 0 32rpx 0 0;
flex-grow: 1;
display: flex;
align-items: center;

text {
color: #70798D;
}
}

@keyframes rotating {
0% {
transform: rotateZ(0deg)
}

100% {
transform: rotateZ(360deg)
}
}

@keyframes rotating_theme3 {
0% {
transform: translate(-50%, -50%) rotateZ(0deg)
}

100% {
transform: translate(-50%, -50%) rotateZ(360deg)
}
}

.hItem {
margin-left: 16rpx;
}

.extrButton {
font-size: 36rpx;
}

.videoPlayer {
position: absolute;
left: 0;
bottom: 0;
z-index: -1;
}
</style>

+ 54
- 0
store/index.js Ver fichero

@@ -0,0 +1,54 @@
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex)

export default new Vuex.Store({
state: {
bgAudioMannager: null,
},
mutations: {
createAudio(state) {
state.bgAudioMannager = uni.getBackgroundAudioManager();
},
setSeekAudio(state, t) {
state.bgAudioMannager.seek(t)
},
// 加载音频监听方法
initAudioMethod (state, obj) {
state.bgAudioMannager.onCanplay(() => {
state.bgAudioMannager.currentTime = obj.currentTime
});
state.bgAudioMannager.onStop(() => {
console.log('停止播放');
});
state.bgAudioMannager.onPause(() => {
console.log('暂停播放');
});
state.bgAudioMannager.onEnded(() => {
//初始化 需要的参数
console.log('自然播放结束事件');
});
state.bgAudioMannager.onError((res) => {
console.log(res.errMsg);
console.log(res.errCode);
});
},
// 停止全局音频播放
stopAduio(state) {
state.bgAudioMannager && state.bgAudioMannager.pause()
if (state.bgAudioMannager && state.bgAudioMannager.src) {
state.bgAudioMannager.src = ''
}
},
},
action: {
}
})

Cargando…
Cancelar
Guardar