123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- <template>
- <view class="audio-wrapper">
- <view :class="[file_url ? 'audio-play' : 'audio-play not-url']" :style="{
- padding: showSlider ? '0px 32rpx' : '',
- width: showSlider ? 'auto' : '',
- justifyContent: showSlider && !showProgress ? 'space-between' : 'center',
- backgroundColor: backgroundColor,
- }" @click="playAudio(file_url)">
- <SvgIcon v-if="!playing" :size="!playing ? 20 : 14" icon-class="audio" />
- <img v-else :src="
- themeColor === 'gray'
- ? 'static/voice_play_gray.png'
- : 'static/voice_play_white.png'
- " class="voice-play" />
- <template v-if="showSlider&&file_url">
- <text class="audio-time" v-if="showProgress"> {{ currentTime }} </text>
- <slider v-if="showProgress" class="audio-slider" v-model="sliderValue" activeColor="#ffffff"
- backgroundColor="#1853C6" block-size="12" @change="onSliderChange" />
- <text class="audio-time"> {{ duration }} </text>
- </template>
- </view>
- </view>
- </template>
- <script>
- import {
- GetFileURLMap
- } from '@/api/api.js';
- import {
- secondFormatConversion
- } from '@/utils/transform';
- export default {
- name: 'AudioPlay',
- props: {
- fileId: {
- type: String,
- required: true,
- },
- themeColor: {
- type: String,
- default: '',
- },
- showSlider: {
- type: Boolean,
- default: false,
- },
- // 是否显示音频进度条
- showProgress: {
- type: Boolean,
- default: true,
- },
- // 播放背景色
- backgroundColor: {
- type: String,
- default: '#165dff',
- },
- isPlaying: {
- type: Boolean,
- default: false,
- },
- questionId: {
- type: String,
- default: '',
- }
- },
- data() {
- return {
- secondFormatConversion,
- file_url: '',
- playing: false,
- audio: uni.createInnerAudioContext(),
- duration: '00:00', //音频时长
- currentTime: '00:00', //当前时长
- sliderValue: 0,
- };
- },
- computed: {
- // iconClass() {
- // return this.audio.paused ? 'audio' : 'audio-stop';
- // },
- },
- watch: {
- fileId: {
- handler(val) {
- var that = this;
- if (!val) return;
- GetFileURLMap({
- file_id_list: [val]
- }).then(({
- url_map
- }) => {
- that.file_url = url_map[val];
- that.audio.src = url_map[val];
- that.playing = false;
- that.currentTime = '00:00';
- that.sliderValue = 0;
- // uni.getSystemInfoSync().platform == 'ios'
- that.audio.onCanplay(() => {
- if (that.audio.duration !== 0) {
- clearInterval(that.intervalID);
- that.duration = that.secondFormatConversion(that.audio.duration) // 总时长
- that.currentTime = that.secondFormatConversion(that.audio.currentTime) // 当前时长
- }
- });
- that.audio.onTimeUpdate(() => {
- that.currentTime = that.secondFormatConversion(that.audio.currentTime);
- if (!that.dragging) { // 避免拖动滑块时自动更新
- that.sliderValue = (that.audio.currentTime / that.audio.duration) * 100;
- }
- })
- });
- },
- immediate: true,
- },
- isPlaying: {
- handler(val) {
- if (!val) {
- this.audio.pause();
- this.playing = false;
- }
- }
- },
- questionId: {
- handler(val) {
- this.audio.pause();
- this.playing = false;
- }
- },
- },
- destroyed() {
- this.audio.pause();
- this.playing = false;
- },
- methods: {
- playAudio() {
- if (!this.file_url) return;
- clearInterval(this.timer);
- if (this.playing) {
- this.audio.pause();
- } else {
- this.audio.play();
- this.timer = setInterval(() => {
- if (this.audio.currentTime > 0 && this.audio.currentTime < this.audio.duration) {
- this.sliderValue = (this.audio.currentTime / this.audio.duration) * 100;
- } else {
- this.playing = !this.playing;
- clearInterval(this.timer);
- }
- }, 1000);
- }
- this.playing = !this.playing;
- if (this.playing)
- uni.$emit('setOtherAudioPlaying', this.fileId, this.playing);
- },
- onSliderChange(event) {
- const value = event.detail.value;
- if (this.audio && this.audio.duration > 0) {
- // 验证 value 是否是有效的百分比值(0-100之间)
- if (isNaN(value) || value < 0 || value > 100) {
- // console.error("Invalid value:", value);
- return;
- }
- // 计算新的位置
- const newPosition = (value / 100) * this.audio.duration;
- // 验证 newPosition 是否是有效的数字,不是 NaN,并且在有效范围内
- if (!isNaN(newPosition) && newPosition >= 0 && newPosition <= this.audio.duration) {
- // 设置音频播放位置
- this.audio.seek(newPosition);
- if (!this.dragging) { // 避免拖动滑块时自动更新
- this.sliderValue = value;
- }
- } else {
- console.error("Invalid newPosition:", newPosition);
- }
- }
- },
- },
- };
- </script>
- <style lang="scss" scoped>
- .audio-wrapper {
- margin: 32rpx 0;
- .audio-play {
- display: flex;
- column-gap: 24rpx;
- align-items: center;
- justify-content: center;
- width: 80rpx;
- height: 80rpx;
- color: #ffffff;
- background-color: $uni-color-main;
- border-radius: 80rpx;
- &.not-url {
- color: #a1a1a1;
- }
- .voice-play {
- width: 40rpx;
- height: 40rpx;
- }
- .audio-time {
- min-width: 70rpx;
- font-size: 24rpx;
- font-weight: 400;
- }
- .audio-slider {
- flex: 2;
- margin: 0;
- }
- }
- }
- </style>
|