vue3+ts+vant制作音乐播放器(进度条拖拽、倍速切换、上一曲、下一曲)完整版
1、进度条的用的是vant的Progress组件,比手写进度条方便很多,有自带的事件
2、H5页面兼容pc
效果展示
上代码
一、template模块
<template lang="pug">
.audioPlay
main
.audioBox
.imgBox
van-image.songImg(
width="4.6rem",
height="4.6rem",
fit="cover",
style="border-radius: 5px; overflow: hidden",
:src="require('@/assets/images/media/song.png')"
)
.titBox 文稿
.titText {{ title }}
.audioControl
audio(
:src="audioSrc",
@canplay="getDuration",
@timeupdate="updateTime",
v-show="false",
controls,
ref="audio"
)
van-slider.audioSlider(
v-model="sliderValue",
@update:model-value="sliderOnChange",
active-color="#D8BE98",
inactive-color="#E0E0E0",
:disabled="isSlide > 0 ? false : true"
)
template(#button)
.custom-button {{ currentDuration }}/{{ duration }}
ul.handleUl
li.handleLi(@click="handleBack")
van-image.handleImg(
width="0.44rem",
height="0.44rem",
fit="cover",
:src="require('@/assets/images/media/houtui.png')"
)
li.handleLi(@click="prevPlay(isPlayNum)")
van-image.handleImg(
width="0.44rem",
height="0.44rem",
fit="cover",
:src="isPlayNum > 1 ? require('@/assets/images/media/prevL.png') : require('@/assets/images/media/prev.png')"
)
li.handleLi(@click="handlePauseOrPlay")
van-image.handleImg(
width="0.98rem",
height="0.98rem",
fit="cover",
:src="paused ? require('@/assets/images/media/play.png') : require('@/assets/images/media/stop.png')"
)
li.handleLi(@click="nextPlay(isPlayNum)")
van-image.handleImg(
width="0.44rem",
height="0.44rem",
fit="cover",
:src="isPlayNum < catalogArray.length ? require('@/assets/images/media/nextL.png') : require('@/assets/images/media/next.png')"
)
li.handleLi(@click="handleForward")
van-image.handleImg(
width="0.44rem",
height="0.44rem",
fit="cover",
:src="require('@/assets/images/media/qianjin.png')"
)
ul.funUl
li.funLi(@click="sheetShowCli('mulu', '选集')")
van-image.funImg(
width="0.54rem",
height="0.54rem",
fit="cover",
:src="require('@/assets/images/media/mulu.png')"
)
p.funtext 目录
li.funLi(@click="sheetShowCli('beisu', '倍速')")
van-image.funImg(
width="0.54rem",
height="0.54rem",
fit="cover",
:src="require('@/assets/images/media/beisu.png')"
)
p.funtext 倍速
li.funLi(
@click="sheetShowCli('pinglun', '评论')"
)
van-image.funImg(
width="0.54rem",
height="0.54rem",
fit="cover",
:src="require('@/assets/images/media/pinglun.png')"
)
p.funtext 评论
li.funLi
van-image.funImg(
width="0.54rem",
height="0.54rem",
fit="cover",
:src="require('@/assets/images/media/shoucang.png')"
)
p.funtext 收藏
li.funLi
van-image.funImg(
width="0.54rem",
height="0.54rem",
fit="cover",
:src="require('@/assets/images/media/dianzan.png')"
)
p.funtext 点赞
van-action-sheet.audioSheet(v-model:show="sheetShow", :title="sheetTit")
.sheetCon
.multipW(v-if="sheetConActive == 'beisu'")
.multipInfo(
v-for="(item, index) in multipleArray",
:key="index",
@click="multipSelect(item.num, index)"
)
.multipText(:class="item.isSelected ? 'isSelect' : ''") {{ item.text }}
van-icon.multipIcon(
:name="require('@/assets/images/media/isSelected.png')",
size="0.7rem",
v-if="item.isSelected"
)
.catalogW(v-if="sheetConActive == 'mulu'")
.catalogInfo(
v-for="(item, index) in catalogArray",
:key="index",
@click="catalogSelect(index)"
)
.catalogCon(:class="item.isPlay ? 'isPlay' : ''")
.con_box
.con_boxTit {{ index + 1 }}.{{ item.title }}
.con_boxDesc {{ item.desc }}
.con_boxIcon
van-icon.timeIcon(name="clock-o", size="0.2rem")
span.timeSpan {{ item.audioDurat }}
van-image.con_Img(
width="0.6rem",
height="0.6rem",
fit="cover",
:src="item.isPlay ? require('@/assets/images/media/playing.gif') : require('@/assets/images/media/playMl.png')"
)
.reviewW(v-if="sheetConActive == 'pinglun'")
.reviewInfo 评论内容
</template>
二、ts部分
<script lang="ts">
import {
defineComponent,
onBeforeMount,
reactive,
ref,
toRefs,
} from "vue"; interface control {
audioUrl: string;
play: boolean;
} export default defineComponent({
name: "audioPlay",
setup() {
const audioControl: control = reactive({ audioUrl: "", play: false });
onBeforeMount(() => {
audioInfo.audioSrc = (catalogArray as any).value[0].audioSrc;
audioInfo.title = (catalogArray as any).value[0].title;
audioInfo.duration = (catalogArray as any).value[0].audioDurat;
setTimeout(() => {
audioInfo.isSlide = audio.value.duration;
console.log("audio.value.duration22", typeof audio.value.duration);
// alert(audio.value.duration);
}, 100);
}); //暂停播放
const handlePlayer = (): void => {
audioControl.play = !audioControl.play;
audioControl.play
? (audio.value as any).play()
: (audio.value as any).pause();
}; const audioInfo = reactive({
audioSrc: "",
backSecond: 15, //后退秒数
forwardSecond: 15, //前进秒数
duration: "00:00", //音频总时长
currentDuration: "00:00", //音频当前播放时长
title: "",
paused: true,
isPlayNum: 1, //上下集用到-正在播放的第几集
isSlide: 0, //判断滑块是否可以滑动
});
const audio = ref();
const sliderValue = ref();
//后退
const handleBack = (): void => {
if (audio.value.currentTime > audioInfo.backSecond) {
audio.value.currentTime =
audio.value.currentTime - audioInfo.backSecond;
}
};
//前进
const handleForward = (): void => {
if (
audio.value.duration - audio.value.currentTime >
audioInfo.forwardSecond
) {
audio.value.currentTime =
audio.value.currentTime + audioInfo.forwardSecond;
}
};
//暂停或播放
const handlePauseOrPlay = (): void => {
console.log("audio.value.duration22", typeof audio.value.duration);
setTimeout(() => {
audio.value.paused ? audio.value.play() : audio.value.pause();
audioInfo.paused = !audioInfo.paused;
}, 200);
};
//视频在可以播放时触发
const getDuration = (): void => {
setTimeout(() => {
(audioInfo.duration as any) = timeFormat(audio.value.duration);
}, 200);
};
//将单位为秒的的时间转换成mm:ss的形式
const timeFormat = (number: Number) => {
let minute = parseInt((<number>number / 60) as any);
let second = parseInt((<number>number % 60) as any);
(minute as any) = minute >= 10 ? minute : "0" + minute;
(second as any) = second >= 10 ? second : "0" + second;
return minute + ":" + second;
};
//进度条发生变化时触发
const updateTime = (): void => {
audioInfo.currentDuration = timeFormat(audio.value.currentTime);
sliderValue.value = (
(audio.value.currentTime * 100) /
audio.value.duration
).toFixed(3);
audioInfo.isSlide = audio.value.duration;
// 播放完毕按钮变回
if (audioInfo.currentDuration == audioInfo.duration) {
audioInfo.paused = true;
}
};
//滑动进度条
const sliderOnChange = (value: any): void => {
console.log("value", timeFormat((audio.value.duration * value) / 100));
// 设置播放时间
audioInfo.currentDuration = timeFormat(
(audio.value.duration * value) / 100
);
audio.value.currentTime = parseInt(
((audio.value.duration * value) / 100) as any
);
};
// 点击右侧功能
const sheetShow = ref(false);
const sheetTit = ref("");
const sheetConActive = ref("");
const multipleArray = ref([
{ num: 0.75, text: "0.75X", isSelected: false },
{ num: 1, text: "1.0X(正常倍速)", isSelected: true },
{ num: 1.25, text: "1.25X", isSelected: false },
{ num: 1.5, text: "1.5X", isSelected: false },
{ num: 2, text: "2X", isSelected: false },
]);
const catalogArray = ref([
{
title: "音频播放器第一曲",
desc: "第一站《大宪章》纪念碑1/4",
audioSrc: require("@/assets/images/media/audio/music1.mp3"),
audioDurat: "04:07",
isPlay: true,
},
{
title: "测试二未过时的未过时仍未未过时的未过时过时的未过时的未过",
desc: "第一站测试二未过时的未过时仍未未过时的未过时过时的未过时的",
audioSrc: require("@/assets/images/media/audio/music2.mp3"),
audioDurat: "02:06",
isPlay: false,
},
{
title: "测试三过时未过时的未过时",
desc: "第一站测试三未过时的未过时仍未未过时的未过时过时的未过时的/4",
audioSrc: require("@/assets/images/media/audio/music3.mp3"),
audioDurat: "04:56",
isPlay: false,
},
]); // 下方功能唤起面板
const sheetShowCli = (val: any, tit: any): void => {
sheetConActive.value = val;
sheetTit.value = tit;
sheetShow.value = true;
};
// 倍速选择
const multipSelect = (num: Number, index: number): void => {
audio.value.playbackRate = num;
multipleArray.value.forEach((item: any) => {
item.isSelected = false;
});
multipleArray.value[index].isSelected = true;
sheetShow.value = false;
};
// 选集功能
const catalogSelect = (index: number): void => {
catalogArray.value.forEach((item: any) => {
item.isPlay = false;
});
sliderValue.value = 0;
audio.value.currentTime = 0;
audioInfo.paused = true;
audioInfo.audioSrc = (catalogArray as any).value[index].audioSrc;
audioInfo.title = (catalogArray as any).value[index].title;
audioInfo.currentDuration = "00:00";
audioInfo.duration = (catalogArray as any).value[index].audioDurat;
catalogArray.value[index].isPlay = true;
sheetShow.value = false;
audioInfo.isPlayNum = index + 1;
handlePauseOrPlay();
};
// 上一集
const prevPlay = (num: any): void => {
if (num > 1) {
catalogArray.value.forEach((item: any) => {
item.isPlay = false;
});
sliderValue.value = 0;
audio.value.currentTime = 0;
audioInfo.paused = true;
audioInfo.audioSrc = (catalogArray as any).value[num - 2].audioSrc;
audioInfo.title = (catalogArray as any).value[num - 2].title;
audioInfo.currentDuration = "00:00";
audioInfo.duration = (catalogArray as any).value[num - 2].audioDurat;
catalogArray.value[num - 2].isPlay = true;
audioInfo.isPlayNum = num - 1;
sheetShow.value = false;
handlePauseOrPlay();
}
};
// 下一集
const nextPlay = (num: any): void => {
if (num < catalogArray.value.length) {
catalogArray.value.forEach((item: any) => {
item.isPlay = false;
});
sliderValue.value = 0;
audio.value.currentTime = 0;
audioInfo.paused = true;
audioInfo.audioSrc = (catalogArray as any).value[num].audioSrc;
audioInfo.title = (catalogArray as any).value[num].title;
audioInfo.currentDuration = "00:00";
audioInfo.duration = (catalogArray as any).value[num].audioDurat;
catalogArray.value[num].isPlay = true;
audioInfo.isPlayNum = num + 1;
sheetShow.value = false;
handlePauseOrPlay();
}
};
return {
...toRefs(audioControl),
handlePlayer, ...toRefs(audioInfo),
handleBack,
handleForward,
handlePauseOrPlay,
getDuration,
updateTime,
audio,
sliderValue,
sliderOnChange,
sheetShow,
multipleArray,
sheetShowCli,
sheetTit,
sheetConActive,
multipSelect,
catalogArray,
catalogSelect,
prevPlay,
nextPlay,
};
},
});
</script>
三、样式部分
<style lang="scss">
.audioSlider {
.van-slider__bar {
z-index: 1111;
}
&.van-slider--disabled {
opacity: 1;
}
}
.isPlay {
.con_Img {
.van-image__img {
width: 0.4rem;
height: 0.4rem;
}
}
}
</style>
<style lang="scss" scoped>
.audioPlay {
height: 100vh;
display: flex;
flex-direction: column;
.content {
@include Padding(0.2rem, 0px);
@include Position(relative, 0, -0.9rem);
width: 100%;
}
main {
flex: 1;
overflow: auto;
.audioBox {
.imgBox {
width: 100%;
text-align: center;
margin-top: 1.1rem;
}
}
.titBox {
width: 1.8rem;
height: 0.6rem;
border-radius: 0.3rem;
border: 1px solid #d8be98;
text-align: center;
margin: 0.6rem auto 0;
font-size: 0.32rem;
line-height: 0.6rem;
color: #d8be98;
box-sizing: border-box;
}
.titText {
width: 80%;
margin: 0.3rem auto 0;
@include textEllipsis();
font-size: 0.36rem;
line-height: 0.4rem;
color: #333;
text-align: center;
}
.audioControl {
position: relative;
&::before {
position: absolute;
top: 0;
left: 0;
width: 50%;
content: "";
height: 2px;
background: #d8be98;
}
&::after {
position: absolute;
top: 0;
right: 0;
width: 50%;
content: "";
height: 2px;
background: #e0e0e0;
}
width: 90%;
position: absolute;
bottom: 0.6rem;
left: 50%;
transform: translateX(-50%);
.audioSlider {
width: 80%;
margin: 0 auto; .custom-button {
background: #d8be98;
padding: 0 0.14rem;
height: 0.36rem;
line-height: 0.4rem;
border-radius: 0.18rem;
font-size: 0.24rem;
color: #000;
transform: scale(0.9);
}
}
.handleUl {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 0.1rem;
box-sizing: border-box;
margin-top: 0.4rem;
.handleLi {
line-height: 0;
}
}
}
.funUl {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 0.7rem;
.funLi {
line-height: 0; .funtext {
color: #999999;
font-size: 0.24rem;
line-height: 0.4rem;
}
}
}
}
.audioSheet {
.sheetCon {
border-top: 1px solid #dfdfdf;
.multipW {
padding: 0 0.32rem 1rem;
.multipInfo {
border-bottom: 1px solid #dfdfdf;
height: 0.86rem;
display: flex;
justify-content: space-between;
align-items: center;
.multipText {
color: #666666;
font-size: 0.32rem;
&.isSelect {
color: #caaa7c;
}
.multipIcon {
color: #caaa7c;
}
}
}
}
.catalogW {
padding: 0 0.32rem 0.6rem;
.catalogInfo {
border-bottom: 1px solid #e6e6e6;
.catalogCon {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.24rem 0.2rem 0.24rem 0;
box-sizing: border-box;
.con_box {
width: 80%;
.con_boxTit {
width: 100%;
@include textEllipsis();
font-size: 0.32rem;
color: #000000;
}
.con_boxDesc {
font-size: 0.28rem;
color: #999999;
@include textEllipsis();
margin-top: 0.1rem;
}
.con_boxIcon {
color: #cccccc;
font-size: 0.24rem;
margin-top: 0.2rem;
.timeIcon {
margin-right: 0.1rem;
}
}
}
&.isPlay {
.con_box {
.con_boxTit {
color: #caaa7c;
}
.con_boxDesc {
color: #e0ccb1;
}
.con_boxIcon {
color: #e0ccb1;
}
}
}
.con_Img {
background: #f7f1e8;
width: 0.6rem;
height: 0.6rem;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
}
}
}
}
.reviewW {
padding: 0 0.32rem 0.6rem;
.reviewInfo {
border-bottom: 1px solid #e6e6e6;
padding: 0.4rem 0;
.reviewCon {
display: flex;
justify-content: space-between;
.con_box {
width: calc(100% - 0.78rem);
.con_boxTit {
font-size: 0.28rem;
color: #666666;
}
.con_boxTime {
color: #b3b3b3;
font-size: 0.24rem;
line-height: 0.4rem;
}
.con_boxText {
font-size: 0.32rem;
color: #333333;
line-height: 0.48rem;
}
.con_boxReply {
background: #f8f8f8;
width: 100%;
padding: 0.1rem 0.2rem 0.2rem;
box-sizing: border-box;
margin-top: 0.2rem;
.replyList {
display: flex;
font-size: 0.28rem;
line-height: 0.36rem;
margin-top: 0.1rem;
.replyName {
color: #666;
white-space: nowrap;
margin-right: 0.1rem;
}
.replyText {
color: #333;
}
}
}
}
}
}
}
}
}
@media only screen and (min-width: 750px) {
.audioPlay {
@include boxSize(750px, 100vh);
margin: 0 auto;
}
}
</style>
做个笔记
vue3+ts+vant制作音乐播放器(进度条拖拽、倍速切换、上一曲、下一曲)完整版的更多相关文章
- HTML+纯JS制作音乐播放器
该篇文章会教你通过JavaScript制作一个简单的音乐播放器.包括播放.暂停.上一曲和下一曲. 阅读本文章你需要对HTML.CSS和Javascript有基本的了解. 话不多说,先上图. emmm. ...
- Android 音视频深入 十三 OpenSL ES 制作音乐播放器,能暂停和调整音量(附源码下载)
项目地址https://github.com/979451341/OpenSLAudio OpenSL ES 是基于NDK也就是c语言的底层开发音频的公开API,通过使用它能够做到标准化, 高性能,低 ...
- Qt+MPlayer音乐播放器开发笔记(一):ubuntu上编译MPlayer以及Demo演示
前言 在ubuntu上实现MPlayer播放器播放音乐. Demo Mplayer MPlayer是一款开源多媒体播放器,以GNU通用公共许可证发布.此款软件 ...
- html5+css3 制作音乐播放器
//css// body , html{ margin:0; padding:0; font:12px Arial, Helvetica, sans-serif; } .Mus ...
- 开源播放器 ijkplayer (二) :ijkplayer倍速变调问题解决方案
转载注明出处:http://www.cnblogs.com/renhui/p/6510872.html 之前使用IjkPlayer做播放器的使用的时候,在做倍速播放的时候,发现播放的声音音调明显变高了 ...
- JavaScript实现水平进度条拖拽效果
<html> <head> <meta charset="UTF-8"> <title>Document</title> ...
- 使用 原生js 制作插件 (javaScript音乐播放器)
1.引用页面 index.html <!DOCTYPE html> <html lang="en"> <head> <meta chars ...
- 【重点突破】——Canvas技术绘制音乐播放器界面
一.引言 在用Canvas练习制作了验证码之后,还有一个用Canvas技术很综合的练习——制作音乐播放器.在做这个练习的过程中,还有一个重要的观察点,那就是理解Canvas的一大问题. 二.要求 点 ...
- ios开发:一个音乐播放器的设计与实现
github地址:https://github.com/wzpziyi1/MusicPlauer 这个Demo,关于歌曲播放的主要功能都实现了的.下一曲.上一曲,暂停,根据歌曲的播放进度动态滚动歌词, ...
- vue实现音乐播放器实战笔记
原文链接:https://blog.csdn.net/Forever201295/article/details/80266600 一.项目说明该播放器的是基于学习vue的实战练习,不用于其他途径.应 ...
随机推荐
- CTF学习笔记(二)
二.常见的HTML知识 (一)rorbts协议 robots协议也称爬虫协议.爬虫规则等,是指网站可建立一个robots.txt文件来告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取,而搜索引擎则通过读 ...
- 实验一-密码引擎-加密API研究
实验一-密码引擎-加密API研究 API:应用程序接口(API:Application Program Interface)是一组定义.程序及协议的集合,通过 API 接口实现计算机软件之间的相互通信 ...
- cnpm 安装不上
以管理员身份运行power shell,输入以下命令: set-ExecutionPolicy RemoteSigned 出现选项之后,输入A,回车,在输入 get-ExecutionPolicy 出 ...
- sequlizejs学习笔记整理
1.事务 try { const transaction = await sequelize.transaction(); const user = await User.findOne(..., { ...
- Pytorch实战学习(二):用Pytorch实现逻辑回归
<PyTorch深度学习实践>完结合集_哔哩哔哩_bilibili 用Pytorch实现逻辑回归 Logistic Regression 从线性回归 → 逻辑回归 1.分类问题 计算属于 ...
- 关于视频加密ts格式转MP4的方法
copy /b "%~dp0"\*.ts "%~dp0"\new.ts 最近在手机浏览器上下载了钢铁侠等漫威电影,觉得不错想保存到手机上,却都又是m3u8格式, ...
- debian最小化安装+sway记录
1. 最小化安装系统,只安装最基础的系统,如果是虚拟机中安装,安装SSH服务器可能更方便在宿主机终端操作客户机.deiban的安装器里有提供基础工具包的安装项,如果为了系统纯净不安装,可能会导致更多不 ...
- 制作win10装机U盘
第一步:准备一个8G容量以上的U盘 第二步:制作系统盘. 进入windows官网 官网win10下载地址:https://www.microsoft.com/zh-cn/software-downlo ...
- docker 操作常用命令
镜像 #以tomcat为基础镜像创建一个容器,容器名为my-tomcat #拉取tomcat最新镜像,实际生产中,docker pull 这一步可以省略,docker run的时候会自己去拉取. do ...
- CCCC L3-032 关于深度优先搜索和逆序对的题应该不会很难吧这件事 【树状数组】
https://pintia.cn/problem-sets/994805046380707840/exam/problems/1518582895035215872 题意 给你一棵树,给定树根,要求 ...