1 <template>
2 <div class="wrapper">
3 <svg
4 t="1673833915638"
5 class="icon rotateIcon"
6 viewBox="0 0 1024 1024"
7 version="1.1"
8 xmlns="http://www.w3.org/2000/svg"
9 p-id="2105"
10 >
11 <path
12 d="M478.388706 45.236706L363.52 2.529882v668.431059a254.674824 254.674824 0 0 0-115.892706 18.010353c-96.015059 39.213176-145.889882 133.541647-118.362353 199.499294 27.587765 66.138353 122.217412 96.617412 218.112 57.404236 73.728-30.117647 124.867765-87.401412 131.553883-142.275765l-0.481883-591.329883c158.238118 48.067765 272.263529 100.773647 272.26353 258.048 0 55.838118 91.557647 109.808941 91.557647-109.146352-0.060235-186.247529-159.804235-298.887529-363.881412-315.934118z"
13 fill="#17966f"
14 p-id="2106"
15 />
16 </svg>
17 <img
18 class="musicIcon"
19 :src="musicList[currentIndex].icon"
20 :style="{ animationPlayState: `${playStatus ? 'running' : 'paused'}` }"
21 />
22 <div class="controls">
23 <div class="controls-title">
24 正在播放中:{{ musicList[currentIndex].singer }} -
25 {{ musicList[currentIndex].song }}
26 </div>
27 <audio
28 ref="audio"
29 :src="musicList[currentIndex].url"
30 @ended="ended"
31 autoplay
32 />
33 <div class="controls-change">
34 <svg
35 t="1673834949112"
36 class="icon"
37 viewBox="0 0 1024 1024"
38 version="1.1"
39 xmlns="http://www.w3.org/2000/svg"
40 p-id="1372"
41 @click="preMusic"
42 >
43 <path
44 d="M76.442058 472.123804l479.972785-344.375282c31.816917-17.080004 68.268577-21.123087 68.295184 44.618197l0 149.899008 271.113573-194.517205c31.815893-17.080004 69.179357-17.590634 68.295184 46.384423l0 676.471912c-0.91078 57.779961-39.127716 66.168002-68.295184 47.295166L624.711051 703.367469l0 148.120502c-0.026607 56.012711-39.127716 65.284889-68.295184 46.411029L76.442058 553.481763C54.339786 531.021216 54.339786 494.597655 76.442058 472.123804zM907.552193 196.359156 568.143437 433.700703c0 0 0-186.833199 0-237.341546L115.598428 512.809435l452.545009 316.465628c0-13.244652 0-237.328243 0-237.328243l339.408757 237.328243C907.552193 816.029388 907.552193 246.867504 907.552193 196.359156z"
45 fill="#0fd7ce"
46 p-id="1373"
47 />
48 </svg>
49 <svg
50 t="1673835088221"
51 class="icon"
52 viewBox="0 0 1024 1024"
53 version="1.1"
54 xmlns="http://www.w3.org/2000/svg"
55 p-id="1230"
56 @click="play"
57 v-if="!playStatus"
58 >
59 <path
60 d="M512 0C230.4 0 0 230.4 0 512s230.4 512 512 512 512-230.4 512-512S793.6 0 512 0z m0 981.333333C253.866667 981.333333 42.666667 770.133333 42.666667 512S253.866667 42.666667 512 42.666667s469.333333 211.2 469.333333 469.333333-211.2 469.333333-469.333333 469.333333z"
61 fill="#0fd7ce"
62 p-id="1231"
63 />
64 <path
65 d="M672 441.6l-170.666667-113.066667c-57.6-38.4-106.666667-12.8-106.666666 57.6v256c0 70.4 46.933333 96 106.666666 57.6l170.666667-113.066666c57.6-42.666667 57.6-106.666667 0-145.066667z"
66 fill="#0fd7ce"
67 p-id="1232"
68 />
69 </svg>
70 <svg
71 t="1673835567808"
72 class="icon"
73 viewBox="0 0 1048 1024"
74 version="1.1"
75 xmlns="http://www.w3.org/2000/svg"
76 p-id="1531"
77 @click="pause"
78 v-else
79 >
80 <path
81 d="M524.272128 0.018022C241.513165 0.018022 12.288102 229.245952 12.288102 512.005018c0 112.734003 36.43904 216.957952 98.17897 301.537997l38.667981-40.258048C97.458176 699.230003 67.143168 609.158963 67.143168 512.005018 67.143168 259.540992 271.807078 54.872986 524.272128 54.872986c252.45696 0 457.120973 204.668006 457.120973 457.132032 0 252.460954-204.664013 457.118003-457.120973 457.118003-96.240026 0-185.530982-29.744026-259.189043-80.53504l-34.539008 42.797978c83.150029 58.344038 184.437965 92.596019 293.728973 92.596019 282.758963 0 511.984026-229.220966 511.984026-511.976038C1036.256154 229.245952 807.031091 0.018022 524.272128 0.018022zM615.693107 256.011981l0 511.987 54.855 0L670.548107 256.012 615.693128 256.012zM377.996083 256.011981l0 511.987 54.855 0L432.851083 256.012 377.996128 256.012z"
82 fill="#0fd7ce"
83 p-id="1532"
84 />
85 </svg>
86 <svg
87 t="1673835103937"
88 class="icon"
89 viewBox="0 0 1024 1024"
90 version="1.1"
91 xmlns="http://www.w3.org/2000/svg"
92 p-id="1381"
93 @click="nextMusic"
94 >
95 <path
96 d="M947.557942 553.481763 467.585156 897.899c-29.166445 18.872836-68.267554 9.601682-68.295184-46.411029L399.289972 703.367469 128.175376 897.899c-29.166445 18.872836-67.384404 10.484795-68.295184-47.295166L59.880192 174.132946c-0.883149-63.975057 36.479291-63.464427 68.295184-46.384423l271.113573 194.517205L399.288949 172.366719c0.02763-65.741283 36.479291-61.698201 68.295184-44.618197l479.973809 344.375282C969.661238 494.597655 969.661238 531.021216 947.557942 553.481763zM116.44883 829.275064l339.408757-237.328243c0 0 0 224.082568 0 237.328243l452.545009-316.465628-452.545009-316.450279c0 50.508347 0 237.341546 0 237.341546L116.44883 196.359156C116.44883 246.867504 116.44883 816.029388 116.44883 829.275064z"
97 fill="#0fd7ce"
98 p-id="1382"
99 />
100 </svg>
101 </div>
102 <div class="controls-progress">
103 <span class="controls-progress-duration"
104 >{{ Math.floor(currentTime / 60) }}:{{
105 Math.floor(currentTime % 60) < 10
106 ? `0${Math.floor(currentTime % 60)}`
107 : Math.floor(currentTime % 60)
108 }}
109 / {{ Math.floor(totalDuration / 60) }}:{{
110 Math.floor(totalDuration % 60) < 10
111 ? `0${Math.floor(totalDuration % 60)}`
112 : Math.floor(totalDuration % 60)
113 }}
114 </span>
115 <input
116 class="controls-progress-range"
117 type="range"
118 :max="totalDuration"
119 :value="currentTime"
120 :style="{
121 backgroundSize: `${(currentTime / totalDuration) * 100}% 100%`
122 }"
123 @change="changePlayProgress"
124 />
125 <svg
126 t="1673839083338"
127 class="icon volume-icon"
128 viewBox="0 0 1024 1024"
129 version="1.1"
130 xmlns="http://www.w3.org/2000/svg"
131 p-id="1290"
132 @click="volumeStatus = !volumeStatus"
133 v-if="!muteStatus"
134 >
135 <path
136 d="M448 938.666667a21.333333 21.333333 0 0 1-15.093333-6.246667L225.833333 725.333333H53.333333a53.393333 53.393333 0 0 1-53.333333-53.333333V352a53.393333 53.393333 0 0 1 53.333333-53.333333h172.5l207.08-207.086667A21.333333 21.333333 0 0 1 469.333333 106.666667v810.666666a21.333333 21.333333 0 0 1-21.333333 21.333334zM53.333333 341.333333a10.666667 10.666667 0 0 0-10.666666 10.666667v320a10.666667 10.666667 0 0 0 10.666666 10.666667h181.333334a21.333333 21.333333 0 0 1 15.086666 6.246666L426.666667 865.833333V158.166667L249.753333 335.086667A21.333333 21.333333 0 0 1 234.666667 341.333333z"
137 fill="#0fd7ce"
138 p-id="1291"
139 />
140 </svg>
141 <svg
142 t="1673845914200"
143 class="icon volume-icon"
144 viewBox="0 0 1024 1024"
145 version="1.1"
146 xmlns="http://www.w3.org/2000/svg"
147 p-id="1440"
148 @click="volumeStatus = !volumeStatus"
149 v-else
150 >
151 <path
152 d="M448 938.666667a21.333333 21.333333 0 0 1-15.093333-6.246667L225.833333 725.333333H53.333333a53.393333 53.393333 0 0 1-53.333333-53.333333V352a53.393333 53.393333 0 0 1 53.333333-53.333333h172.5l207.08-207.086667A21.333333 21.333333 0 0 1 469.333333 106.666667v810.666666a21.333333 21.333333 0 0 1-21.333333 21.333334zM53.333333 341.333333a10.666667 10.666667 0 0 0-10.666666 10.666667v320a10.666667 10.666667 0 0 0 10.666666 10.666667h181.333334a21.333333 21.333333 0 0 1 15.086666 6.246666L426.666667 865.833333V158.166667L249.753333 335.086667A21.333333 21.333333 0 0 1 234.666667 341.333333z m964.42 377.753334a21.333333 21.333333 0 0 0 0-30.173334L840.833333 512l176.92-176.913333a21.333333 21.333333 0 1 0-30.173333-30.173334L810.666667 481.833333 633.753333 304.913333a21.333333 21.333333 0 0 0-30.173333 30.173334L780.5 512l-176.92 176.913333a21.333333 21.333333 0 0 0 30.173333 30.173334L810.666667 542.166667l176.913333 176.92a21.333333 21.333333 0 0 0 30.173333 0z"
153 fill="#0fd7ce"
154 p-id="1441"
155 />
156 </svg>
157 <input
158 v-if="volumeStatus"
159 type="range"
160 class="volume-range"
161 :value="volume"
162 max="100"
163 :style="{ backgroundSize: `${(volume / 100) * 100}% 100%` }"
164 @change="changeVolume"
165 />
166 </div>
167 </div>
168 </div>
169 </template>
170 <script lang="ts" setup>
171 import { onMounted, ref } from "vue";
172 const musicList: any[] = [
173 {
174 id: 26445261,
175 url: "https://apis.jxcxin.cn/api/kuwo?id=26445261&type=mp3",
176 icon: "https://img4.kuwo.cn/star/albumcover/500/12/73/1352603132.jpg",
177 singer: "买辣椒也用券",
178 song: "起风了(旧版)"
179 },
180 {
181 id: 60262165,
182 url: "https://apis.jxcxin.cn/api/kuwo?id=60262165&type=mp3",
183 icon: "https://img4.kuwo.cn/star/albumcover/500/28/0/866943227.jpg",
184 singer: "尚士达",
185 song: "生而为人"
186 },
187 {
188 id: 5961360,
189 url: "https://apis.jxcxin.cn/api/kuwo?id=5961360&type=mp3",
190 icon: "https://img1.kuwo.cn/star/albumcover/500/59/77/2376077807.jpg",
191 singer: "胡彦斌",
192 song: "月光"
193 },
194 {
195 id: 19519910,
196 url: "https://apis.jxcxin.cn/api/kuwo?id=19519910&type=mp3",
197 icon: "https://img1.kuwo.cn/star/albumcover/500/26/56/3241621283.jpg",
198 singer: "胡彦斌",
199 song: "诀别诗"
200 },
201 {
202 id: 158104409,
203 url: "https://apis.jxcxin.cn/api/kuwo?id=158104409&type=mp3",
204 icon: "https://img1.kuwo.cn/star/albumcover/500/58/72/3795397878.jpg",
205 singer: "蓝心羽",
206 song: "阿拉斯加海湾"
207 },
208 {
209 id: 178937138,
210 url: "https://apis.jxcxin.cn/api/kuwo?id=178937138&type=mp3",
211 icon: "https://img2.kuwo.cn/star/albumcover/500/60/49/2041460549.jpg",
212 singer: "LKer林柯",
213 song: "满目星辰皆是你"
214 }
215 ];
216 // 播放器实例
217 const audio = ref(null);
218 const playStatus = ref(false);
219 const currentIndex = ref(0);
220 let timer = null;
221 // 播放
222 const play = () => {
223 clearInterval(timer);
224 audio.value.play();
225 playStatus.value = true;
226 getMusicDuration();
227 currentTime.value = Math.floor(audio.value.currentTime) || 0;
228 timer = setInterval(() => {
229 currentTime.value++;
230 if (currentTime.value >= totalDuration.value) clearInterval(timer);
231 }, 1000);
232 };
233 // 暂停
234 const pause = () => {
235 audio.value.pause();
236 playStatus.value = false;
237 clearInterval(timer);
238 };
239
240 // 播放结束
241 const ended = () => {
242 if (currentIndex.value >= musicList.length - 1) {
243 currentIndex.value = 0;
244 return;
245 }
246 currentIndex.value++;
247 };
248 // 上一曲
249 const preMusic = () => {
250 currentTime.value = 0;
251 if (currentIndex.value === 0) {
252 currentIndex.value = musicList.length - 1;
253 play();
254 return;
255 }
256 currentIndex.value--;
257 play();
258 };
259 // 下一曲
260 const nextMusic = () => {
261 currentTime.value = 0;
262 if (currentIndex.value === musicList.length - 1) {
263 currentIndex.value = 0;
264 play();
265 return;
266 }
267 currentIndex.value++;
268 play();
269 };
270 // 拖动进度
271 const changePlayProgress = (event: any) => {
272 currentTime.value = event.target.value;
273 audio.value.currentTime = currentTime.value;
274 };
275 // 静音
276 const muteStatus = ref(false);
277 const volume = ref(10);
278 const volumeStatus = ref(false);
279 const changeVolume = (e: any) => {
280 volume.value = e.target.value;
281 volume.value == 0 ? (muteStatus.value = true) : (muteStatus.value = false);
282 audio.value.volume = volume.value / 100;
283 volumeStatus.value = false;
284 };
285 // duration
286 const currentTime = ref(0);
287 const totalDuration = ref(100);
288 const getMusicDuration = () => {
289 if (![2, 3, 4].includes(audio.value.readyState)) return;
290 setTimeout(() => {
291 totalDuration.value = Math.floor(audio.value.duration);
292 }, 2000);
293 };
294 // 初始化
295 onMounted(() => {
296 getMusicDuration();
297 audio.value.volume = volume.value / 100;
298 audio.value.addEventListener("play", () => {
299 play();
300 });
301 });
302 </script>
303 <style scoped>
304 .wrapper {
305 display: flex;
306 align-items: center;
307 border-radius: 10px;
308 width: 460px;
309 background-image: linear-gradient(to right, white, #63ff63);
310 margin-bottom: 300px;
311 }
312 .wrapper .rotateIcon {
313 width: 20px;
314 height: 40px;
315 transform: translateY(-40px) translateX(18px);
316 }
317 .icon {
318 width: 20px;
319 height: 40px;
320 }
321 .musicIcon {
322 width: 120px;
323 height: 120px;
324 border-radius: 50%;
325 border: 4px solid white;
326 animation: rotateIcon 6s linear infinite backwards;
327 }
328 @keyframes rotateIcon {
329 from {
330 transform: rotate(0deg);
331 }
332 to {
333 transform: rotate(360deg);
334 }
335 }
336 .controls {
337 display: flex;
338 flex: 1;
339 flex-direction: column;
340 align-items: center;
341 padding: 20px;
342 }
343 .controls .controls-title {
344 color: #348eb1;
345 font-size: 12px;
346 }
347 .controls .controls-change {
348 display: flex;
349 justify-content: space-between;
350 margin-top: 10px;
351 width: 100%;
352 }
353 .controls .controls-change .icon {
354 width: 30px;
355 cursor: pointer;
356 }
357 .controls .controls-progress {
358 display: flex;
359 width: 100%;
360 align-items: center;
361 font-size: 12px;
362 position: relative;
363 }
364 .controls .controls-progress .controls-progress-duration {
365 color: #0f9cd3;
366 }
367 .controls .controls-progress .controls-progress-range {
368 flex: 1;
369 margin: 0 20px;
370 outline: none;
371 -webkit-appearance: none;
372 background: -webkit-linear-gradient(#cc0ceb, #dc01ff) no-repeat, #ddd;
373 height: 3px;
374 }
375 .controls .controls-progress .controls-progress-range::-webkit-slider-thumb {
376 -webkit-appearance: none;
377 height: 16px;
378 width: 16px;
379 background: #f8f9fa;
380 border-radius: 50%;
381 border: solid 1px #ddd;
382 }
383 .controls .controls-progress .icon {
384 cursor: pointer;
385 }
386 .volume-range {
387 position: absolute;
388 right: 0;
389 transform: rotate(-90deg) translate(40px, 18px);
390 outline: none;
391 -webkit-appearance: none;
392 background: -webkit-linear-gradient(#d5601c, #ff6308) no-repeat, #ddd;
393 height: 3px;
394 width: 60px;
395 }
396 .controls .controls-progress .volume-range::-webkit-slider-thumb {
397 -webkit-appearance: none;
398 height: 14px;
399 width: 4px;
400 background: #f8f9fa;
401 border-radius: 50%;
402 border: solid 1px #ddd;
403 }
404 </style>

展开

手写一个audio播放器,实现歌曲切换,列表歌曲循环,音量调节等 vue组件的更多相关文章

  1. 用 EPWA 写一个 图片播放器 PicturePlayer

    用 EPWA 写一个 图片播放器  PicturePlayer  . 有关 EPWA,见 <我发起并创立了一个 EPWA 的 开源项目>   https://www.cnblogs.com ...

  2. 从零开始学习PYTHON3讲义(十四)写一个mp3播放器

    <从零开始PYTHON3>第十四讲 通常来说,Python解释执行,运行速度慢,并不适合完整的开发游戏.随着电脑速度的快速提高,这种情况有所好转,但开发游戏仍然不是Python的重点工作. ...

  3. 师兄写的一个JAVA播放器的源代码(转)

    师兄写的一个JAVA播放器的源代码 MediaPlayer.java------------------------------------------------------------------ ...

  4. 大半宿,封装了一个MP3播放器的类,写了个简陋的播放器

    用 winmm.lib 写的 封装不是很好,而且没有优化,效率可能有问题,但是现在几乎没有什么大问题 我用我封装的类,写了一个小播放器,界面上的所有功能都实现了,包括双击列表中的文件名,直接播放文件 ...

  5. python 拼写检查代码(怎样写一个拼写检查器)

    原文:http://norvig.com/spell-correct.html 翻译:http://blog.youxu.info/spell-correct.html 怎样写一个拼写检查器 Pete ...

  6. 利用SpringBoot+Logback手写一个简单的链路追踪

    目录 一.实现原理 二.代码实战 三.测试 最近线上排查问题时候,发现请求太多导致日志错综复杂,没办法把用户在一次或多次请求的日志关联在一起,所以就利用SpringBoot+Logback手写了一个简 ...

  7. 手写一个简单的ElasticSearch SQL转换器(一)

    一.前言 之前有个需求,是使ElasticSearch支持使用SQL进行简单查询,较新版本的ES已经支持该特性(不过貌似还是实验性质的?) ,而且git上也有elasticsearch-sql 插件, ...

  8. 看年薪50W的架构师如何手写一个SpringMVC框架

    前言 做 Java Web 开发的你,一定听说过SpringMVC的大名,作为现在运用最广泛的Java框架,它到目前为止依然保持着强大的活力和广泛的用户群. 本文介绍如何用eclipse一步一步搭建S ...

  9. 吴裕雄--天生自然python学习笔记:python 用pygame模块制作一个音效播放器

    用 Sound 对象制作一个音效播放器. 应用程序总览 程序在执行后默认会把 WAV 音频文件加载到清单中,单击“播放”按钮可开始 播放,同时显示 “正在播放 xxx 音效”的信息 . 播放过程中,可 ...

  10. 剖析手写Vue,你也可以手写一个MVVM框架

    剖析手写Vue,你也可以手写一个MVVM框架# 邮箱:563995050@qq.com github: https://github.com/xiaoqiuxiong 作者:肖秋雄(eddy) 温馨提 ...

随机推荐

  1. Fastjsonfan反序列化(一)

    前置知识 Fastjson 是一个 Java 库,可以将 Java 对象转换为 JSON 格式,当然它也可以将 JSON 字符串转换为 Java 对象. Fastjson 可以操作任何 Java 对象 ...

  2. Azure DevOps Server 用户组加入 Azure AD Domain Service 管理用户

    一,引言 今天我们继续讲解 Azure DevOps Server 的内容,对于管理用户组除了在 Azure DevOps Server 服务器上添加管理员方式外,还有没有其他方式,Azure Dev ...

  3. 【Shell案例】【!~//、grep反向查找、sed流编辑器】13、去掉所有包含this的句子

    描述写一个 bash脚本以实现一个需求,去掉输入中含有this的语句,把不含this的语句输出示例:假设输入如下:that is your bagis this your bag?to the deg ...

  4. Django框架:1、手撸web框架、Django框架简介、安装与使用和小白必会三板斧

    Django框架 目录 Django框架 一.Django推导流程 1.纯手撸web框架 2.基于wsgire模块 3.代码封装优化 4.动静态网页 5.jinja2模块 6.前端.后端.数据库三者联 ...

  5. java调用python脚本 并传参(根据配置文件获取python文件地址)

    方式一: Java代码 package com.mybatis.plus.utils; import cn.hutool.core.lang.Console; import java.io.Buffe ...

  6. Typora快捷键--实用

    一.字体编辑 大小:ctr + 数字 或 ctr + 加减号 或 ### 加粗:ctr + b 倾斜:ctr + i 下划线:ctr + u 删除线:alt + shift + 5 上标:^ + 字体 ...

  7. 高性能 Jsonpath 框架,Snack3 3.2.50 发布

    Snack3,一个高性能的 JsonPath 框架 借鉴了 Javascript 所有变量由 var 申明,及 Xml dom 一切都是 Node 的设计.其下一切数据都以ONode表示,ONode也 ...

  8. Jmeter 之在linux中监控Memory、CPU、I/O资源等操作方法

    在做性能测试时,单纯的只看响应时间.错误率.中间值远远不够的,有时需要监控服务cpu.内存等指标来判断影响性能的瓶颈在哪. 操作步骤: 一.Linux下配置jmeter环境 1.在linux环境下安装 ...

  9. JavaScript:操作符:算术运算符(加减乘除模幂)及其隐式转换数据类型

    加法+ 减法- 乘法* 除法/ 模运算% 幂运算**,即a ** b求的是a的b次方 执行上述运算时,当两个操作数有非数字时,JS会隐式转换为数字,再进行运算: 一些特殊的非数字,会进行如下转换: t ...

  10. freeswitch的gateway配置方案

    概述 freeswitch是一款简单好用的VOIP开源软交换平台. 在voip的网络模型中,网关是我们经常会遇到的概念. 在freeswitch中,如何配置gateway,如何使用好gateway的模 ...