audioList.vue 8.24 KB
<template>
  <div class="audio-list-page">
    <van-config-provider :theme-vars="themeVars">
      <van-floating-panel v-model:height="info_height" :anchors="anchors" @height-change="onHeightChange">
        <template #header>
          <div style="display: flex; align-items: center; justify-content: space-between; padding: 1.25rem 1rem 0.5rem 1rem;">
            <van-icon name="https://cdn.ipadbiz.cn/bieyuan/map/icon/Group%2054@3x.png" color="#DD7850" size="1.25rem" />
            <van-icon @click="onClose" name="cross" color="#DD7850" size="1.25rem" />
          </div>
        </template>
        <!-- <page-info ref="pageInfo" :info="itemInfo" :height="info_height" @close-float="onCloseFloat" @route="onRoute"></page-info> -->
        <!-- <div v-if="showClose" @click="closeFloatPanel" class="close-float-panel">
          <van-icon name="arrow-left" color="#FFF" size="1.5rem" />
        </div> -->
        <div class="van-hairline--top" style="padding: 1rem;">
          <div v-for="(item, index) in audio_list" :key="index" class="van-hairline--bottom audio-item">
            <div :class="['point', audio_index === index ? 'checked' : '']"></div>
            <div :class="['text', audio_index === index ? 'checked' : '', 'van-ellipsis']">
              {{ index + 1 }}. {{ item.title }}<span v-if="item.play" class="text-center">正在播放</span>

            </div>
            <!-- <div style="border: 1px solid #DD7850; border-radius: 50%; padding: 0.25rem;">
              <van-icon v-if="audio_index === index" name="https://cdn.ipadbiz.cn/xys/map/%E6%92%AD%E6%94%BE@2x.png" size="1.75rem" />
              <van-icon v-else name="https://cdn.ipadbiz.cn/xys/map/%E6%92%AD%E6%94%BE%E6%9A%82%E5%81%9C@2x.png" size="1.75rem" />
            </div> -->
            <div class="progress-ring">
              <div class="circle">
                <div class="pause-icon">
                  <van-icon @click="handleAudioPause(item, index)" v-if="item.play" name="https://cdn.ipadbiz.cn/xys/map/%E6%92%AD%E6%94%BE@2x.png" size="2.25rem" />
                  <van-icon @click="handleAudioPlay(item, index)" v-else name="https://cdn.ipadbiz.cn/xys/map/%E6%92%AD%E6%94%BE%E6%9A%82%E5%81%9C@2x.png" size="2.25rem" />
                </div>
                <div :class="['progress', item.play ? 'checked' : '']"></div>
              </div>
            </div>
          </div>
        </div>
      </van-floating-panel>
    </van-config-provider>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { useRoute, useRouter } from 'vue-router';
import $ from 'jquery';

const props = defineProps({
  height: Number,
});

const themeVars = ref({
  floatingPanelHeaderHeight: 0,
  floatingPanelBorderRadius: '1.25rem'
})

const anchors = ref([0, (0.2 * window.innerHeight),  (0.5 * window.innerHeight)]);

const onHeightChange = ({ height }) => {
  if (!height) {
    onClose()
  }
}

const info_height = ref(0);

watch(
  () => props.height,
  (v) => {
    info_height.value = v;
  }
)

const onClose = () => {
  audio.value.pause();
  pauseProgress();
  // 播放进度条
  $('.progress').css('background', 'conic-gradient(#f07142 0%, transparent 0%)');
  audio_list.value.forEach(item => item.play = false);
  emit('close');
}

const emit = defineEmits(['close']);

const audio_index = ref();

const audio_list = ref([]);

onMounted(() => {
  audio_list.value = [
    {
      title: '3',
      src: 'https://img.tukuppt.com/newpreview_music/01/62/01/63b515415b482633.mp3',
      play: false
    },
    {
      title: '2',
      src: 'https://img.tukuppt.com/newpreview_music/01/66/20/63c0c3db3f8de739.mp3',
      play: false
    },
    {
      title: '风纺声(测试)(风的声音)风纺声(测试)(风的声音)',
      src: 'https://img.tukuppt.com/newpreview_music/01/65/86/63c0264040bd4441.mp3',
      play: false
    },
  ];

  let audioDuration = 60; // 音频总时长 (秒)
  let elapsedTime = 0;    // 已播放的时间

  // nextTick(() => {
  //   setPlayProgress(30)
  // })

});

const audio = ref(new Audio());
const duration = ref(0);      // 音频总时长
const currentTime = ref(0);   // 当前播放时间
// let audioDuration = 30; // 音频总时长 (秒)
let elapsedTime = 0;    // 已播放的时间
let intervalId = null;  // 保存setInterval的ID


// 函数:更新进度条
function updateProgress(audioDuration, index) {
  let progressPercent = (elapsedTime / audioDuration) * 100;
  document.querySelector('.progress.checked').style.background =
    `conic-gradient(#f07142 ${progressPercent}%, transparent ${progressPercent}%)`;

  if (elapsedTime >= audioDuration) {
    clearInterval(intervalId); // 音频播放完成,停止更新
    let idx = index + 1;
    if (idx >= audio_list.value.length) {
      idx = 0;
    }
    handleAudioPlay(audio_list.value[idx], idx)
  }
}

// 函数:启动进度更新
function startProgress(audioDuration, index) {
  intervalId = setInterval(() => {
    elapsedTime++;
    updateProgress(audioDuration, index);
  }, 1000);
}

// 函数:暂停进度更新
function pauseProgress() {
  clearInterval(intervalId);
}

// 初始化进度条
// startProgress();

// const handleAudio = (item, index) => {
//   audio_index.value = index;
//   document.querySelector('.progress').style.background =
//   `conic-gradient(#f07142 0%, transparent 0%)`;
//   clearInterval(progressInterval); // 音频播放完成
//   setPlayProgress(item.duration);
// }

const handleAudioPause = (item, index) => {
  item.play = false;
  audio.value.pause();
  pauseProgress();
}

const updateDuration = () => {
  duration.value = Math.floor(audio.value.duration); // 获取音频时长
};

const updateTime = () => {
  currentTime.value = Math.floor(audio.value.currentTime); // 获取当前播放时间
};

// 监听 'loadedmetadata' 事件,确保在音频元数据加载后获取时长
audio.value.addEventListener('loadedmetadata', updateDuration);

// 监听 'timeupdate' 事件,实时更新当前播放时间
audio.value.addEventListener('timeupdate', updateTime);

const handleAudioPlay = (item, index) => {
  // 播放状态
  audio_list.value.forEach(item => item.play = false);
  if (audio_index.value !== index) {
    audio.value.src = item.src;
  }
  // 播放进度条
  $('.progress').css('background', 'conic-gradient(#f07142 0%, transparent 0%)')
  clearInterval(intervalId);
  let play_status = audio.value.play() // 播放
  if (play_status) {
    play_status.then(() => {
      item.play = true;
      // 存放到pinia里面控制
      // store.changeAudio(audio.value);
      // store.changeAudioSrc(audio.value.src);
      // store.changeAudioStatus('play');
      //
      startProgress(duration.value, index);
      if (audio_index.value === index) { // 点击同一音频
      } else {
        audio_index.value = index;
        elapsedTime = 0
      }
    }).catch((e) => {
      // 失败
      console.log('Operation is too fast, audio play fails')
    })
  }
}
</script>

<style lang="less" scoped>
.audio-list-page {
  .audio-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 1rem 0;
    .point {
      padding: 0.25rem;
      width: 1rem;
      height: 1rem;
      border-radius: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      margin-right: 1rem;
      &.checked {
        border: 1px solid rgba(221, 120, 80, 0.5);
      }
      &::after {
        content: '';
        width: 1rem;
        height: 1rem;
        border-radius: 50%;
        background-color: #DD7850;
      }
    }
    .text {
      flex: 1;
      // display: flex;
      align-items: center;
      color: #47525F99;
      &.checked {
        color: #47525F;
      }
      .text-center {
        color: #DD7850;
        font-size: 0.85rem;
        margin-left: 1rem;
        line-height: 1.25;
      }
    }
  }

  .progress-ring {
  position: relative;
  width: 2.5rem;
  height: 2.5rem;
}

.circle {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  // background-color: lightgray;
}

.pause-icon {
  z-index: 10;
  position: absolute;
  left:0.15rem;
  top: 0.15rem;
}

.progress {
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  border-radius: 50%;
  background: conic-gradient(#f07142 0%, #f07142 0%, transparent 0%);
  z-index: 5;
  transform: rotate(0deg); /* 让进度条从顶部开始 */
}
}
</style>