|
- <template>
- <view class="imt-audio" :class="[`${theme}`]" v-if="audiolist.length > 0">
-
- <template v-if="theme == 'theme4'">
- <view class="imt-audios">
- <view class="audio-wrapper">
- <view class="audio-flex">
- <text>
- {{renderData('current')}}
- </text>
- <slider class="audio-slider" :activeColor="themeColor" block-size="16"
- :value="renderData('current_value')" :max="renderData('duration_value')" @change="change"
- :disabled="!renderIsPlay"></slider>
- <text v-if="!duration">
- {{renderData('duration')}}
- </text>
- <text v-else>{{ duration }}</text>
- </view>
- </view>
- </view>
-
- <view class="forward">
- <view style="flex-grow: 1;display: flex;align-items: center;">
- <view class="forward-item">
- <!-- 块退15s -->
- <image :src="require('./static/prev.png')" class="prevbtn" @click="stepPlay(-15)"
- mode="widthFix">
- </image>
- </view>
- <view class="forward-item top audio-control-wrapper">
- <image :src="require('./static/loading.png')" v-if="loading" class="play loading"></image>
- <template v-else>
- <image :src="require('./static/pausebtn.png')" alt="" @click="operate" class="play"
- v-if="renderData('paused')"></image>
- <image :src="require('./static/playbtn.png')" alt="" @click="operate" class="play" v-else>
- </image>
- </template>
- </view>
- <view class="forward-item" style="margin-left: 0;">
- <!-- 快进15s -->
- <image :src="require('./static/next.png')" class="nextbtn" @click="stepPlay(15)"
- mode="widthFix">
- </image>
- </view>
- <view class="forward-item" style="margin-left: 0;">
- <block v-for="(data, index) in playbackRateArr" :key="index">
- <text class="playbackRate" @tap="checkPlaybackRate(data.name, index)"
- :class="{act: playbackRateIndex == index}">x{{ data.name }}</text>
- </block>
- </view>
-
- </view>
- <view class="forward-item" style="flex-shrink: 0;">
- <image @tap="showMenu" :src="require('./static/quanping.png')" mode=""></image>
- </view>
- </view>
- </template>
-
-
- <template v-if="theme == 'theme3'">
- <slider class="audio-slider" :activeColor="themeColor" block-size="0" :value="renderData('current_value')"
- :max="renderData('duration_value')" @change="change" :disabled="!renderIsPlay"></slider>
-
- <view class="top">
- <view class="audio-control-wrapper">
- <image :src="renderData('coverImgUrl')" mode="aspectFill" class="cover"
- :class="{ on: !renderData('paused') }"></image>
-
- <image :src="require('./static/loading.png')" v-if="loading" class="play loading"></image>
- <template v-else>
- <image :src="require('./static/pausebtn.png')" alt="" @click="operate" class="play"
- v-if="renderData('paused')"></image>
- <image :src="require('./static/playbtn.png')" alt="" @click="operate" class="play" v-else>
- </image>
- </template>
- </view>
- </view>
- <view class="audio-wrapper">
- <view class="titlebox">
- <view class="title">{{ renderData('title') }}</view>
- <view class="singer">{{ renderData('singer') }}</view>
- </view>
-
- <view class="slidebox">
- <view>{{ renderData('current') }}/ {{ renderData('duration') }}</view>
- <view>
- <text @click="changeplay(-1)">上一首</text>
- <text @click="changeplay(1)">下一首</text>
- </view>
- </view>
- </view>
- </template>
-
- <template v-if="theme == 'theme2'">
- <view class="top">
- <view class="audio-control-wrapper" :style="{backgroundImage: `url(${renderData('coverImgUrl')})`}">
- <image :src="require('./static/loading.png')" v-if="loading" class="play loading"></image>
- <template v-else>
- <image :src="require('./static/pausebtn.png')" alt="" @click="operate" class="play"
- v-if="renderData('paused')"></image>
- <image :src="require('./static/playbtn.png')" alt="" @click="operate" class="play" v-else>
- </image>
- </template>
- </view>
-
- <view>
- <view class="title">
- <text>{{ renderData('title') }}</text>
- <view class="audio-number">{{ renderData('current') }}/{{ renderData('duration') }}</view>
- </view>
- <view class="singer">{{ renderData('singer') }}</view>
- </view>
- </view>
- </template>
-
- <template v-if="theme == 'theme1'">
- <view class="top">
- <view class="audio-control-wrapper">
- <image :src="renderData('coverImgUrl')" mode="aspectFill" class="cover"
- :class="{ on: !renderData('paused') }"></image>
- </view>
-
- <view>
- <view class="title">{{ renderData('title') }}</view>
- <view class="singer">{{ renderData('singer') }}</view>
- </view>
- </view>
- <view class="audio-wrapper">
- <view class="audio-number">{{ renderData('current') }}</view>
- <slider class="audio-slider" :activeColor="themeColor" block-size="16"
- :value="renderData('current_value')" :max="renderData('duration_value')" @change="change"
- :disabled="!renderIsPlay"></slider>
- <view class="audio-number">{{ renderData('duration') }}</view>
- </view>
-
- <view class="audio-button-box">
- <!-- 块退15s -->
- <image :src="require('./static/prev.png')" class="prevbtn" @click="stepPlay(-15)" mode="widthFix">
- </image>
- <!-- 上一首 -->
- <image :src="require('./static/go.png')" class="prevplay" @click="changeplay(-1)" mode="widthFix">
- </image>
- <div class="playbox">
- <image :src="require('./static/loading2.png')" v-if="loading" class="play loading"></image>
- <template v-else>
- <!-- 播放 -->
- <image :src="require('./static/playbtn2.png')" alt="" @click="operate" class="play"
- v-if="renderData('paused')"></image>
- <!-- 暂停 -->
- <image :src="require('./static/pausebtn2.png')" alt="" @click="operate" class="pause" v-else>
- </image>
- </template>
- </div>
- <!-- 下一首 -->
- <image :src="require('./static/go.png')" class="nextplay" @click="changeplay(1)" mode="widthFix">
- </image>
- <!-- 快进15s -->
- <image :src="require('./static/next.png')" class="nextbtn" @click="stepPlay(15)" mode="widthFix">
- </image>
- </view>
- </template>
-
- <u-popup v-model="screenShow" mode="center" borderRadius="16">
- <view class="middles">
- <view class="audio-flex">
- <view class="scroll-box" @touchstart="touchS" @touchend="touchE">
- <view class="slider-container">
- <view class="place-box" :style="{height: `${boxHeight}%`}"></view>
- <view class="slider-btn"></view>
- </view>
- </view>
- </view>
-
- <view class="forwards">
- <view class="imt-audioss">
-
- <view class="forward-item texts">
- <text>
- {{renderData('current') || '00:00:00'}}
- </text>
- </view>
-
-
- <view class="forward-item">
- <image :src="require('./static/prev.png')" class="prevbtn" @click="stepPlay(-15)"
- mode="widthFix">
- </image>
- </view>
- <view class="forward-item top">
- <view class="audio-control-wrapper">
- <image :src="require('./static/loading.png')" v-if="loading" class="play loading">
- </image>
- <template v-else>
- <image :src="require('./static/pausebtn.png')" alt="" @click="operate" class="play"
- v-if="renderData('paused')"></image>
- <image :src="require('./static/playbtn.png')" alt="" @click="operate" class="play"
- v-else>
- </image>
- </template>
- </view>
- </view>
- <view class="forward-item">
- <image :src="require('./static/next.png')" class="nextbtn" @click="stepPlay(15)"
- mode="widthFix">
- </image>
- </view>
-
- <view class="forward-item">
- <text v-if="!duration">
- {{renderData('duration') || '00:00:00'}}
- </text>
- <text v-else>{{ duration || '00:00:00' }}</text>
- </view>
-
- <view class="forward-item" style="margin-left: 0;">
- <block v-for="(data, index) in playbackRateArr" :key="index">
- <text class="playbackRate" @tap="checkPlaybackRate(data.name, index)"
- :class="{act: playbackRateIndex == index}">x{{ data.name }}</text>
- </block>
- </view>
-
- </view>
- </view>
-
- <view class="forward-item ms-close" style="flex-shrink: 0;">
- <image @tap="screenShow = false" :src="require('./static/quxiaoquanping.png')" mode="">
- </image>
- </view>
- </view>
- </u-popup>
- </view>
- </template>
-
- <script>
- import ZAudio from './index.js'
- export default {
- props: {
- theme: {
- type: String, // 主题 'theme1' or 'theme2'
- default: 'theme1'
- },
- themeColor: {
- type: String,
- default: '#2671E2'
- },
- duration: {
- type: String,
- default: ""
- }
- },
- data() {
- return {
- playinfo: this.$zaudio.playinfo,
- audiolist: this.$zaudio.audiolist,
- paused: this.$zaudio.paused,
- renderIsPlay: this.$zaudio.renderIsPlay,
- audio: this.$zaudio.renderinfo,
- loading: this.$zaudio.loading,
- action: Symbol('zaudio'),
- screenShow: false, // 记得改回来
-
- pageY: 0, // 滑块按钮位置
- boxHeight: 0, // 染色盒子背景色
- scrollBoxH: 1, // 容器高度
-
- nowInfo: {}, // 当前播放info
- scrollObjS: {}, // 滚动对象
-
- playbackRateArr: [{
- name: 1,
- },
- // {
- // name: 1.25,
- // },
- {
- name: 1.5,
- },
- // {
- // name: 1.75,
- // },
- {
- name: 2,
- },
- ], // 倍速播放
- playbackRateIndex: 0, // 倍速播放下标
- };
- },
- computed: {
- renderData() {
- return name => {
- if (!this.renderIsPlay) {
- if (name == 'paused') {
- return true;
- }
- return this.audio[name];
- } else {
- if (name == 'paused') {
- return this.paused;
- }
- return this.playinfo[name];
- }
- };
- },
-
-
- },
- mounted() {
- this.$nextTick(() => {
- let action = this.action;
- this.$zaudio.syncStateOn(action, ({
- audiolist,
- paused,
- playinfo,
- renderIsPlay,
- renderinfo,
- loading,
- }) => {
- this.audiolist = audiolist;
- this.paused = paused;
- this.playinfo = playinfo;
- this.renderIsPlay = renderIsPlay;
- this.audio = renderinfo;
- this.loading = loading;
- });
- this.$zaudio.syncRender()
-
- this.playbackRateIndex = this.playbackRateArr.findIndex(item => {
- return item.name == (uni.getBackgroundAudioManager().playbackRate || 1)
- })
- });
- },
-
- methods: {
- // 切换倍速播放
- checkPlaybackRate(playbackRate, index) {
- this.playbackRateIndex = index
- this.$zaudio.stop()
- uni.getBackgroundAudioManager().playbackRate = Number(playbackRate)
- this.$emit('checkPlaybackRate')
- },
-
- selectorQuery() {
- const query = uni.createSelectorQuery().in(this);
- query.select('.slider-container').boundingClientRect(data => {
- console.log(data.height, 'scrollBoxH')
- this.scrollBoxH = Math.floor(data.height)
- }).exec();
- },
-
- touchS(e) {
- console.log(e, 'touchS')
- this.scrollObjS = Math.floor(e.changedTouches[0].clientY)
- },
- touchE(e) {
- console.log(e, 'touchE')
- let endObj = Math.floor(e.changedTouches[0].clientY)
- let percent = Math.floor(((endObj - this.scrollObjS) / this.scrollBoxH) * 100)
- if ((this.boxHeight + percent) > 100) {
- this.boxHeight = 100
- } else if ((this.boxHeight + percent) < 0) {
- this.boxHeight = 0
- } else {
- this.boxHeight += percent
- }
-
- let seek = Math.trunc((this.boxHeight / 100) * this.nowInfo.duration_value)
- console.log(seek, 'seek')
- this.$zaudio.seek(seek)
- },
-
- showMenu() {
- this.screenShow = true
- this.$nextTick(() => {
- this.selectorQuery()
- console.log(this.renderData('current_value'), '123')
- console.log(this.renderData('duration_value'), '321')
- this.$zaudio.on('playing', '123', (obj) => {
- this.nowInfo = obj
- this.boxHeight = Math.trunc((Math.trunc(obj.current_value) / Math.trunc(obj
- .duration_value)) * 100)
- })
- })
- },
- // 转换时间
- 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}`;
- },
-
- //播放or暂停
- operate() {
- this.$zaudio.operate();
- },
- //进度拖到
- change(event) {
- if (this.renderIsPlay) {
- this.$zaudio.seek(event.detail.value);
- }
- },
- //快进
- stepPlay(value) {
- if (this.renderData('current') == '00:00:00') return
- console.log(this.renderData('current'))
- this.$zaudio.stepPlay(value);
- },
- //切歌
- changeplay(count) {
- this.$zaudio.changeplay(count);
- }
- },
- beforeDestroy() {
- this.$zaudio.playinfo.duration = '00:00:00'
- this.$zaudio.playinfo.duration_value = '00:00:00'
- //组件卸载时卸载业务逻辑
- let action = this.action;
- this.$zaudio.syncStateOff(action)
- this.$zaudio.stop()
- this.$zaudio.off('playing', '123')
- }
- };
- </script>
-
- <style scoped lang="scss">
- @import './index.scss';
-
- // #ifdef MP-WEIXIN
- .theme3 .audio-slider {
- margin-top: -8px !important;
- }
-
- // #endif
-
-
- @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-audios {
- 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: 44rpx;
- height: 44rpx;
- z-index: 99;
- border-radius: 50%;
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
-
- &.loading {
- width: 48rpx;
- height: 48rpx;
- animation: rotating_theme3 2s linear infinite;
- }
- }
- }
-
- .forward {
- padding: 0 20rpx 20rpx;
- width: 100%;
- display: flex;
- align-items: flex-end;
-
- .forward-item {
- margin-right: 20rpx;
- display: flex;
- align-items: center;
-
- .playbackRate {
- margin: 0 10rpx;
- // padding: 0 10rpx;
- width: 55rpx;
- height: 55rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 24rpx;
-
- &.act {
- color: #2671E2;
- border: 5rpx solid #2671E2;
- border-radius: 50%;
- }
- }
-
- image {
- width: 50rpx;
- height: 50rpx;
- }
- }
- }
-
- .audio-flex {
- padding: 0 16rpx 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)
- }
- }
- </style>
|