hookehuyr

🐞 fix: 音频组件代码整理

...@@ -8,10 +8,6 @@ ...@@ -8,10 +8,6 @@
8 <van-icon @click="onClose" name="cross" color="#DD7850" size="1.25rem" /> 8 <van-icon @click="onClose" name="cross" color="#DD7850" size="1.25rem" />
9 </div> 9 </div>
10 </template> 10 </template>
11 - <!-- <page-info ref="pageInfo" :info="itemInfo" :height="info_height" @close-float="onCloseFloat" @route="onRoute"></page-info> -->
12 - <!-- <div v-if="showClose" @click="closeFloatPanel" class="close-float-panel">
13 - <van-icon name="arrow-left" color="#FFF" size="1.5rem" />
14 - </div> -->
15 <div class="van-hairline--top" style="padding: 1rem;"> 11 <div class="van-hairline--top" style="padding: 1rem;">
16 <div v-for="(item, index) in audio_list" :key="index" class="van-hairline--bottom audio-item"> 12 <div v-for="(item, index) in audio_list" :key="index" class="van-hairline--bottom audio-item">
17 <div :class="['point', audio_index === index ? 'checked' : '']"></div> 13 <div :class="['point', audio_index === index ? 'checked' : '']"></div>
...@@ -19,15 +15,11 @@ ...@@ -19,15 +15,11 @@
19 {{ index + 1 }}. {{ item.title }}<span v-if="item.play" class="text-center">正在播放</span> 15 {{ index + 1 }}. {{ item.title }}<span v-if="item.play" class="text-center">正在播放</span>
20 16
21 </div> 17 </div>
22 - <!-- <div style="border: 1px solid #DD7850; border-radius: 50%; padding: 0.25rem;">
23 - <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" />
24 - <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" />
25 - </div> -->
26 <div class="progress-ring"> 18 <div class="progress-ring">
27 <div class="circle"> 19 <div class="circle">
28 <div class="pause-icon"> 20 <div class="pause-icon">
29 - <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" /> 21 + <van-icon @click="handleAudioPause(item, index)" v-if="item.play" name="https://cdn.ipadbiz.cn/bieyuan/map/icon/pauseButton@3x.png" size="2.05rem" />
30 - <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" /> 22 + <van-icon @click="handleAudioPlay(item, index)" v-else name="https://cdn.ipadbiz.cn/bieyuan/map/icon/play@3x.png" size="2.05rem" />
31 </div> 23 </div>
32 <div :class="['progress', item.play ? 'checked' : '']"></div> 24 <div :class="['progress', item.play ? 'checked' : '']"></div>
33 </div> 25 </div>
...@@ -43,9 +35,15 @@ ...@@ -43,9 +35,15 @@
43 import { ref } from 'vue' 35 import { ref } from 'vue'
44 import { useRoute, useRouter } from 'vue-router'; 36 import { useRoute, useRouter } from 'vue-router';
45 import $ from 'jquery'; 37 import $ from 'jquery';
38 +import { storeToRefs } from 'pinia'
39 +import { mainStore } from '@/store';
40 +
41 +const store = mainStore();
42 +const { audio_status, audio_entity } = storeToRefs(store);
46 43
47 const props = defineProps({ 44 const props = defineProps({
48 height: Number, 45 height: Number,
46 + status: String,
49 }); 47 });
50 48
51 const themeVars = ref({ 49 const themeVars = ref({
...@@ -55,23 +53,32 @@ const themeVars = ref({ ...@@ -55,23 +53,32 @@ const themeVars = ref({
55 53
56 const anchors = ref([0, (0.2 * window.innerHeight), (0.5 * window.innerHeight)]); 54 const anchors = ref([0, (0.2 * window.innerHeight), (0.5 * window.innerHeight)]);
57 55
58 -const onHeightChange = ({ height }) => { 56 +const onHeightChange = ({ height }) => { // 监听高度变化
59 - if (!height) { 57 + if (!height) { // 关闭
60 - onClose() 58 + onClose();
61 } 59 }
62 } 60 }
63 61
64 const info_height = ref(0); 62 const info_height = ref(0);
65 63
64 +
65 +
66 watch( 66 watch(
67 () => props.height, 67 () => props.height,
68 (v) => { 68 (v) => {
69 info_height.value = v; 69 info_height.value = v;
70 } 70 }
71 ) 71 )
72 - 72 +// watch(
73 -const onClose = () => { 73 +// () => props.status,
74 - audio.value.pause(); 74 +// (v) => {
75 +// if (v) { // 监听详情页播放状态,关闭浮层音频播放
76 +// }
77 +// }
78 +// )
79 +
80 +const onClose = () => { // 关闭列表回调
81 + audio.value.pause(); // 暂停音频播放
75 pauseProgress(); 82 pauseProgress();
76 // 播放进度条 83 // 播放进度条
77 $('.progress').css('background', 'conic-gradient(#f07142 0%, transparent 0%)'); 84 $('.progress').css('background', 'conic-gradient(#f07142 0%, transparent 0%)');
...@@ -79,7 +86,7 @@ const onClose = () => { ...@@ -79,7 +86,7 @@ const onClose = () => {
79 emit('close'); 86 emit('close');
80 } 87 }
81 88
82 -const emit = defineEmits(['close']); 89 +const emit = defineEmits(['close', 'status']);
83 90
84 const audio_index = ref(); 91 const audio_index = ref();
85 92
...@@ -103,114 +110,135 @@ onMounted(() => { ...@@ -103,114 +110,135 @@ onMounted(() => {
103 play: false 110 play: false
104 }, 111 },
105 ]; 112 ];
106 -
107 - let audioDuration = 60; // 音频总时长 (秒)
108 - let elapsedTime = 0; // 已播放的时间
109 -
110 - // nextTick(() => {
111 - // setPlayProgress(30)
112 - // })
113 -
114 }); 113 });
115 114
115 +/**
116 + * 音频播放模块
117 + */
118 +
116 const audio = ref(new Audio()); 119 const audio = ref(new Audio());
117 const duration = ref(0); // 音频总时长 120 const duration = ref(0); // 音频总时长
118 -const currentTime = ref(0); // 当前播放时间 121 +// const currentTime = ref(0); // 当前播放时间
119 -// let audioDuration = 30; // 音频总时长 (秒)
120 let elapsedTime = 0; // 已播放的时间 122 let elapsedTime = 0; // 已播放的时间
121 let intervalId = null; // 保存setInterval的ID 123 let intervalId = null; // 保存setInterval的ID
122 124
123 - 125 +/**
124 -// 函数:更新进度条 126 +* 更新进度条
125 -function updateProgress(audioDuration, index) { 127 +*/
128 +const updateProgress = (audioDuration, index) => {
126 let progressPercent = (elapsedTime / audioDuration) * 100; 129 let progressPercent = (elapsedTime / audioDuration) * 100;
127 document.querySelector('.progress.checked').style.background = 130 document.querySelector('.progress.checked').style.background =
128 `conic-gradient(#f07142 ${progressPercent}%, transparent ${progressPercent}%)`; 131 `conic-gradient(#f07142 ${progressPercent}%, transparent ${progressPercent}%)`;
129 132
130 if (elapsedTime >= audioDuration) { 133 if (elapsedTime >= audioDuration) {
131 - clearInterval(intervalId); // 音频播放完成,停止更新 134 + pauseProgress(); // 音频播放完成,停止更新
135 + // 切换到下一个音频
132 let idx = index + 1; 136 let idx = index + 1;
133 if (idx >= audio_list.value.length) { 137 if (idx >= audio_list.value.length) {
134 idx = 0; 138 idx = 0;
135 } 139 }
136 - handleAudioPlay(audio_list.value[idx], idx) 140 + // 播放下一个音频
141 + handleAudioPlay(audio_list.value[idx], idx);
137 } 142 }
138 } 143 }
139 144
140 -// 函数:启动进度更新 145 +/**
141 -function startProgress(audioDuration, index) { 146 +* 启动进度更新
147 +*/
148 +const startProgress = (audioDuration, index) => {
142 intervalId = setInterval(() => { 149 intervalId = setInterval(() => {
143 elapsedTime++; 150 elapsedTime++;
144 updateProgress(audioDuration, index); 151 updateProgress(audioDuration, index);
145 }, 1000); 152 }, 1000);
146 } 153 }
147 154
148 -// 函数:暂停进度更新 155 +/**
149 -function pauseProgress() { 156 +* 暂停进度更新
157 +*/
158 +const pauseProgress = () => {
150 clearInterval(intervalId); 159 clearInterval(intervalId);
151 } 160 }
152 161
153 -// 初始化进度条 162 +/**
154 -// startProgress(); 163 + * 暂停播放回调
155 - 164 + * @param item
156 -// const handleAudio = (item, index) => { 165 + * @param index
157 -// audio_index.value = index; 166 + */
158 -// document.querySelector('.progress').style.background =
159 -// `conic-gradient(#f07142 0%, transparent 0%)`;
160 -// clearInterval(progressInterval); // 音频播放完成
161 -// setPlayProgress(item.duration);
162 -// }
163 -
164 const handleAudioPause = (item, index) => { 167 const handleAudioPause = (item, index) => {
165 - item.play = false; 168 + item.play = false; // 更新播放状态
166 - audio.value.pause(); 169 + audio.value.pause(); // 暂停音频播放
167 - pauseProgress(); 170 + pauseProgress(); // 暂停进度更新
168 } 171 }
169 172
170 const updateDuration = () => { 173 const updateDuration = () => {
171 duration.value = Math.floor(audio.value.duration); // 获取音频时长 174 duration.value = Math.floor(audio.value.duration); // 获取音频时长
172 }; 175 };
173 176
174 -const updateTime = () => { 177 +// const updateTime = () => {
175 - currentTime.value = Math.floor(audio.value.currentTime); // 获取当前播放时间 178 +// currentTime.value = Math.floor(audio.value.currentTime); // 获取当前播放时间
176 -}; 179 +// };
177 180
178 // 监听 'loadedmetadata' 事件,确保在音频元数据加载后获取时长 181 // 监听 'loadedmetadata' 事件,确保在音频元数据加载后获取时长
179 audio.value.addEventListener('loadedmetadata', updateDuration); 182 audio.value.addEventListener('loadedmetadata', updateDuration);
180 183
181 // 监听 'timeupdate' 事件,实时更新当前播放时间 184 // 监听 'timeupdate' 事件,实时更新当前播放时间
182 -audio.value.addEventListener('timeupdate', updateTime); 185 +// audio.value.addEventListener('timeupdate', updateTime);
183 - 186 +
187 +/*********************************** END *************************************/
188 +/**
189 + * 播放音频回调
190 + * @param item
191 + * @param index
192 + */
184 const handleAudioPlay = (item, index) => { 193 const handleAudioPlay = (item, index) => {
185 - // 播放状态 194 + audio_list.value.forEach(item => item.play = false); // 清空播放状态
186 - audio_list.value.forEach(item => item.play = false);
187 if (audio_index.value !== index) { 195 if (audio_index.value !== index) {
188 audio.value.src = item.src; 196 audio.value.src = item.src;
189 } 197 }
190 - // 播放进度条 198 + // 后台有播放器运行时,先暂停
191 - $('.progress').css('background', 'conic-gradient(#f07142 0%, transparent 0%)') 199 + if (audio_status.value === 'play'){
192 - clearInterval(intervalId); 200 + audio_entity.value.pause();
201 + }
202 + $('.progress').css('background', 'conic-gradient(#f07142 0%, transparent 0%)'); // 清空进度条
203 + pauseProgress(); // 暂停进度更新
193 let play_status = audio.value.play() // 播放 204 let play_status = audio.value.play() // 播放
194 if (play_status) { 205 if (play_status) {
195 play_status.then(() => { 206 play_status.then(() => {
196 item.play = true; 207 item.play = true;
197 // 存放到pinia里面控制 208 // 存放到pinia里面控制
198 - // store.changeAudio(audio.value); 209 + store.changeAudio(audio.value);
199 - // store.changeAudioSrc(audio.value.src); 210 + store.changeAudioSrc(audio.value.src);
200 - // store.changeAudioStatus('play'); 211 + store.changeAudioStatus('play');
201 // 212 //
202 - startProgress(duration.value, index); 213 + startProgress(duration.value, index); // 开始更新进度
203 - if (audio_index.value === index) { // 点击同一音频 214 + if (audio_index.value !== index) { // 点击非同一音频
204 - } else {
205 audio_index.value = index; 215 audio_index.value = index;
206 - elapsedTime = 0 216 + elapsedTime = 0; // 重置已播放时间
207 } 217 }
218 + emit('status', 'play');
208 }).catch((e) => { 219 }).catch((e) => {
209 // 失败 220 // 失败
210 console.log('Operation is too fast, audio play fails') 221 console.log('Operation is too fast, audio play fails')
211 }) 222 })
212 } 223 }
213 } 224 }
225 +
226 +const voicePause = () => {
227 + audio.value.pause();
228 + pauseProgress(); // 暂停进度更新
229 + store.changeAudioStatus('pause');
230 +}
231 +
232 +watch(
233 + () => audio_status.value,
234 + (v) => {
235 + if (v === 'pause') {
236 + voicePause();
237 + audio_list.value.forEach(item => item.play = false);
238 + }
239 + },
240 + { immediate: true }
241 +);
214 </script> 242 </script>
215 243
216 <style lang="less" scoped> 244 <style lang="less" scoped>
......
1 <!-- 1 <!--
2 * @Date: 2024-09-15 22:08:49 2 * @Date: 2024-09-15 22:08:49
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2024-10-08 17:37:42 4 + * @LastEditTime: 2024-10-09 11:06:12
5 * @FilePath: /map-demo/src/views/bieyuan/info.vue 5 * @FilePath: /map-demo/src/views/bieyuan/info.vue
6 * @Description: 文件描述 6 * @Description: 文件描述
7 --> 7 -->
...@@ -80,7 +80,7 @@ ...@@ -80,7 +80,7 @@
80 80
81 <van-back-top /> 81 <van-back-top />
82 82
83 - <audio-play-list :height="audio_list_height" @close="onCloseAudioList"></audio-play-list> 83 + <audio-play-list :height="audio_list_height" :status="audio_status" @close="onCloseAudioList" @status="onStatusAudioList"></audio-play-list>
84 </div> 84 </div>
85 </template> 85 </template>
86 86
...@@ -135,22 +135,22 @@ const images = ref([ ...@@ -135,22 +135,22 @@ const images = ref([
135 const active = ref(0); 135 const active = ref(0);
136 const play_audio_index = ref(null); 136 const play_audio_index = ref(null);
137 137
138 -const audioList = ref([{ 138 +// const audioList = ref([{
139 - text: '5分钟观呼吸', 139 +// text: '5分钟观呼吸',
140 - src: 'https://cdn.ipadbiz.cn/bieyuan/map/audio/%E6%AD%A3%E5%BF%B5%E5%91%BC%E5%90%B8%EF%BC%8810%E5%88%86%E9%92%9F%EF%BC%89.mp3', 140 +// src: 'https://cdn.ipadbiz.cn/bieyuan/map/audio/%E6%AD%A3%E5%BF%B5%E5%91%BC%E5%90%B8%EF%BC%8810%E5%88%86%E9%92%9F%EF%BC%89.mp3',
141 - play: false, 141 +// play: false,
142 -}, { 142 +// }, {
143 - text: '10分钟正念静坐', 143 +// text: '10分钟正念静坐',
144 - src: 'https://cdn.ipadbiz.cn/bieyuan/map/audio/%E5%8D%81%E5%88%86%E9%92%9F%E6%AD%A3%E5%BF%B5%E9%9D%99%E5%9D%9020210510.mp3', 144 +// src: 'https://cdn.ipadbiz.cn/bieyuan/map/audio/%E5%8D%81%E5%88%86%E9%92%9F%E6%AD%A3%E5%BF%B5%E9%9D%99%E5%9D%9020210510.mp3',
145 - play: false, 145 +// play: false,
146 -}, { 146 +// }, {
147 - text: '15分钟正念静坐', 147 +// text: '15分钟正念静坐',
148 - src: 'https://cdn.ipadbiz.cn/bieyuan/map/audio/%E5%8D%81%E5%88%86%E9%92%9F%E6%AD%A3%E5%BF%B5%E9%9D%99%E5%9D%9020210510.mp3', 148 +// src: 'https://cdn.ipadbiz.cn/bieyuan/map/audio/%E5%8D%81%E5%88%86%E9%92%9F%E6%AD%A3%E5%BF%B5%E9%9D%99%E5%9D%9020210510.mp3',
149 - play: false, 149 +// play: false,
150 -}]) 150 +// }])
151 151
152 const playAudio = (item, index) => { 152 const playAudio = (item, index) => {
153 - audioList.value.forEach(item => item.play = false); 153 + page_details.value.experience_audio.forEach(item => item.play = false);
154 audio.value.src = item.src; 154 audio.value.src = item.src;
155 // 后台有播放器运行时,先暂停 155 // 后台有播放器运行时,先暂停
156 if (audio_status.value === 'play'){ 156 if (audio_status.value === 'play'){
...@@ -159,9 +159,7 @@ const playAudio = (item, index) => { ...@@ -159,9 +159,7 @@ const playAudio = (item, index) => {
159 play_audio_index.value = index; 159 play_audio_index.value = index;
160 let play_status = audio.value.play() // 播放 160 let play_status = audio.value.play() // 播放
161 if (play_status) { 161 if (play_status) {
162 - console.warn('start');
163 play_status.then(() => { 162 play_status.then(() => {
164 - console.warn('success');
165 item.play = true; 163 item.play = true;
166 // 存放到pinia里面控制 164 // 存放到pinia里面控制
167 store.changeAudio(audio.value); 165 store.changeAudio(audio.value);
...@@ -317,7 +315,7 @@ watch( ...@@ -317,7 +315,7 @@ watch(
317 (v) => { 315 (v) => {
318 if (v === 'pause') { 316 if (v === 'pause') {
319 voicePause(); 317 voicePause();
320 - audioList.value.forEach(item => item.play = false); 318 + page_details.value.experience_audio?.forEach(item => item.play = false);
321 } 319 }
322 }, 320 },
323 { immediate: true } 321 { immediate: true }
...@@ -370,6 +368,13 @@ const onClickAudioList = () => { ...@@ -370,6 +368,13 @@ const onClickAudioList = () => {
370 const onCloseAudioList = () => { 368 const onCloseAudioList = () => {
371 audio_list_height.value = 0; 369 audio_list_height.value = 0;
372 } 370 }
371 +
372 +const onStatusAudioList = (status) => { // 音频列表组件,状态改变
373 + page_details.value.experience_audio?.forEach(item => item.play = false);
374 + audio.value.pause();
375 + play_audio_index.value = null;
376 + store.changeAudioStatus('pause');
377 +}
373 </script> 378 </script>
374 379
375 <style lang="less"> 380 <style lang="less">
......