暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

我用 HTML 和 JavaScript 实现了一个音乐播放器

前端新世界 2022-02-16
799
喜欢就关注我们吧


本文翻译自:
https://dev.to/kunaal438/how-to-create-music-player-with-pure-html-css-js-34lc

今天我们将看到如何使用HTML、CSS 和JS,来轻松地创建一个音乐播放器。制作的音乐播放器将分为三个部分。主屏幕、播放器屏幕和播放列表部分。主页部分有一个平滑的工作滑块,可以水平滚动。这个音乐播放器最突出的一个优点是可以最小化。是的,可以最小化和最大化播放器本身使得这个项目成为了一个很棒的音乐播放器。

代码

虽然这不是NodeJs应用程序,但我们在写代码之前也应该看看它的文件夹结构。

有一个名为data.js
的文件。该文件包含音乐相关的数据。具体如下所示:

let songs = [
    {
        name'song 1',
        path'assets/musics/Song 1.mp3',
        artist'artist 1',
        cover'assets/images/cover 1.png'
    },
    {
        name'song 2',
        path'assets/musics/Song 2.mp3',
        artist'artist 2',
        cover'assets/images/cover 2.png'
    },
    // +6 more
]

废话不多说,让我们开始对播放器的主页部分进行编码。

主页部分

打开index.html
并开始编写基本的HTML结构。还要链接style.css
和两个JS文件。记得在app.js
之前添加data.js
文件,否则我们将无法访问数据。

链接完所有文件后,我们要创建的第一样东西是音乐封面图片轮播区域carousel
。body标签内部的代码如下。

<!-- home section -->

<section class="home-section">
    <!-- carousel -->
    <div class="carousel">
        <img src="assets/images/cover 1.png" class="active" alt="">
        <img src="assets/images/cover 2.png" alt="">
        <img src="assets/images/cover 3.png" alt="">
        <img src="assets/images/cover 4.png" alt="">
        <img src="assets/images/cover 5.png" alt="">
    </div>
</section>

注意:carousel
包装在home-section
元素中。

@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700;900&display=swap');

*{
    margin0;
    padding0;
    box-sizing: border-box;
}

:root{
    --background#141414;
    --text-color#fff;
    --primary-color#63ff69;
    --secondary-color#000;
    --alpha-colorrgba(0000.5);
    --shadow0 15px 40px var(--alpha-color);
}

html{
    backgroundvar(--background);
    display: flex;
    justify-content: center;
}

body{
    width100%;
    height100vh;
    max-width375px;
    position: relative;
    backgroundvar(--background);
    font-family'roboto', sans-serif;
    colorvar(--text-color);
}

::-webkit-scrollbar{
    display: none;
}

/* home section */

.home-section{
    width100%;
    padding20px;
    height100%;
    padding-bottom100px;
    overflow-y: auto;
}

/* carousel */

.carousel{
    width100%;
    height200px;
    overflow: hidden;
    border-radius20px;
    box-shadowvar(--shadow);
    position: relative;
}

.carousel img{
    position: absolute;
    width100%;
    height100%;
    object-fit: cover;
    opacity0;
    transition1s;
}

.carousel img.active{
    opacity1;
}

你可以看到我们使用了CSS变量,这是为了方便我们将来更改音乐播放器的主题。

输出

请注意,这是为移动视图而设计的,这也是我之所以使用chrome调试器来查看移动端尺寸的原因。

现在创建水平滚动的播放列表。在homde-section
内部:

<h1 class="heading">recently played</h1>
<div class="playlists-group">
    <div class="playlist-card">
        <img src="assets/images/cover 9.png" class="playlist-card-img" alt="">
        <p class="playlist-card-name">top international</p>
    </div>
    <div class="playlist-card">
        <img src="assets/images/cover 2.png" class="playlist-card-img" alt="">
        <p class="playlist-card-name">BTS collection</p>
    </div>
    //+3 more
</div>
<h1 class="heading">based on your listening</h1>
<div class="playlists-group">
    <div class="playlist-card">
        <img src="assets/images/cover 11.png" class="playlist-card-img" alt="">
        <p class="playlist-card-name">top international</p>
    </div>
    <div class="playlist-card">
        <img src="assets/images/cover 12.png" class="playlist-card-img" alt="">
        <p class="playlist-card-name">BTS collection</p>
    </div>
    //+3 more
</div>

.heading{
    margin30px 0 10px;
    text-transform: capitalize;
    font-weight400;
    font-size30px;
}

/* playlists card */

.playlists-group{
    position: relative;
    width100%;
    min-height200px;
    height: auto;
    display: flex;
    flex-wrap: nowrap;
    overflow-x: auto;
}

.playlist-card{
    flex0 0 auto;
    max-width150px;
    height100%;
    margin-right20px;
}

.playlist-card-img{
    width100%;
    height150px;
    object-fit: cover;
    border-radius20px;
}

.playlist-card-name{
    width100%;
    text-align: justify;
    font-size20px;
    text-transform: capitalize;
    padding5px;
}

输出

我们完成了主页部分。但是carousel
不起作用,怎么办呢?打开app.js
文件编写如下代码。

///// carousels/////////////////

const carousel = [...document.querySelectorAll('.carousel img')];

let carouselImageIndex = 0;

const changeCarousel = () => {
    carousel[carouselImageIndex].classList.toggle('active');

    if(carouselImageIndex >= carousel.length - 1){
        carouselImageIndex = 0;
    } else{
        carouselImageIndex++;
    }

    carousel[carouselImageIndex].classList.toggle('active');
}

setInterval(() => {
    changeCarousel();
}, 3000);

你可以看到我们首先选择carousel
元素,并且在每3秒后切换图片的active
类。

现在让我们来制作播放器部分。

播放器

首先实现最小化视图。

<section class="music-player-section">

    <img src="assets/images/back.png" class="back-btn icon hide" alt="">
    <img src="assets/images/nav.png" class="nav-btn icon hide" alt="">

    <h1 class="current-song-name">song 1</h1>
    <p class="artist-name hide">artist 1</p>

    <img src="assets/images/cover 1.png" class="cover hide" alt="">

    <div class="seek-bar-container">
        <input type="range" class="music-seek-bar" value="0">
        <p class="current-time hide">00 : 00</p>
        <p class="duration hide">00 : 00</p>
    </div>

    <div class="controls">
        <span class="fas fa-redo"></span>
        <div class="main">
            <i class="fas fa-backward active"></i>
            <i class="fas fa-play active"></i>
            <i class="fas fa-pause"></i>
            <i class="fas fa-forward active"></i>
        </div>
        <input type="range" class="volume-slider" max="1" value="1" step="0.1">
        <span class="fas fa-volume-up"></span>
    </div>

</section>

仔细看播放器结构,你会发现我们为这些元素设置了hide
类。hide
类表示元素在最小化视图中会隐藏起来。我们为所有元素提供了相同的类,因此我们可以轻松地在CSS中设置它们的样式。

music player */

/* minimize view */

.music-player-section{
    width100%;
    height100px;
    position: fixed;
    bottom0;
    left0;
    backgroundvar(--alpha-color);
    backdrop-filterblur(50px);
    transition1s;
}

.music-seek-bar{
    -webkit-appearance: none;
    width100%;
    position: absolute;
    top: -4px;
    height8px;
    backgroundvar(--secondary-color);
    overflow: hidden;
}

.music-seek-bar::-webkit-slider-thumb{
    -webkit-appearance: none;
    height10px;
    width5px;
    backgroundvar(--primary-color);
    cursor: pointer;
    box-shadow: -400px 0 0 400px var(--primary-color);
}

.current-song-name{
    font-weight300;
    font-size20px;
    text-align: center;
    margin-top5px;
    text-transform: capitalize;
}

.controls{
    position: relative;
    width80%;
    margin: auto;
    display: flex;
    justify-content: center;
    align-items: center;
    height60px;
    font-size30px;
}

.controls span{
    display: none;
    opacity0;
    transition1s;
}

.music-player-section.active .controls{
    justify-content: space-between;
}

.music-player-section.active .controls span{
    font-size25px;
    display: block;
    opacity0.5;
}

.music-player-section.active .controls span.active{
    colorvar(--primary-color);
    opacity1;
}

.controls .main i{
    margin0 5px;
    display: none;
}

.controls .main i.active{
    display: inline;
}

这些样式仅用于最小化视图。

输出

现在让我们创建最大化视图的样式。

/* maximize music player styles */

.music-player-section .hide{
    display: none;
    opacity0;
    transition1s;
}

.music-player-section.active .hide{
    display: block;
    opacity1;
}

.music-player-section.active{
    width100%;
    height100%;
    padding30px;
    display: flex;
    flex-direction: column;
}

.music-player-section.active .music-seek-bar{
    position: relative;
    display: block;
    border-radius50px;
    margin: auto;
}

.music-player-section.active .current-song-name{
    font-size40px;
}

.music-player-section.active .controls{
    width100%;
    font-size50px;
}

.artist-name{
    text-align: center;
    font-size20px;
    text-transform: capitalize;
}

.cover{
    width30vh;
    height30vh;
    object-fit: cover;
    margin: auto;
    border-radius20px;
    box-shadowvar(--shadow);
}

.current-time{
    position: absolute;
    margin-top5px;
    left30px;
}

.duration{
    position: absolute;
    margin-top5px;
    right30px;
}

.icon{
    position: absolute;
    top60px;
    transformscale(1.3);
}

.back-btn{
    left40px;
}

.nav-btn{
    right40px;
}

/* volume button */

.volume-slider{
    -webkit-appearance: none;
    width100px;
    height40px;
    position: absolute;
    right: -35px;
    bottom80px;
    transformrotate(-90deg);
    border-radius20px;
    backgroundvar(--alpha-color);
    overflow: hidden;
    opacity0;
    display: none;
}

.volume-slider.active{
    opacity1;
    display: block;
}

.volume-slider::-webkit-slider-thumb{
    -webkit-appearance: none;
    height40px;
    width10px;
    backgroundvar(--primary-color);
    box-shadow: -200px 0 1px 200px var(--primary-color);
}

要检查这些样式,像这样将active
类添加到music-player-section

<section class="music-player-section active">
...
</section>

输出

之后我们会让这个播放器运行起来。现在让我们从播放器部分删除这个active
类,然后开始创建播放列表部分。

播放列表部分

<section class="playlist active">

    <img src="assets/images/back.png" class="back-btn icon" alt="">

    <h1 class="title">playlist</h1>

    <div class="queue active">
        <div class="queue-cover">
            <img src="assets/images/cover 1.png" alt="">
            <i class="fas fa-pause"></i>
        </div>
        <p class="name">song 1</p>
    </div>
    // +7 more
</section>

/* playlist section */

.playlist{
    width100%;
    height100%;
    position: fixed;
    top0;
    right: -100%;
    padding30px 0;
    backgroundvar(--background);
    z-index3;
    transition1s;
    overflow: auto;
}

.playlist.active{
    right0;
}

.title{
    font-weight300;
    font-size40px;
    text-align: center;
    margin-top15px;
    text-transform: capitalize;
    margin-bottom30px;
}

.queue{
    width100%;
    height80px;
    padding0 30px;
    display: flex;
    align-items: center;
    border-top2px solid var(--alpha-color);
}

.queue-cover{
    width60px;
    height60px;
    border-radius10px;
    overflow: hidden;
    margin-right20px;
    position: relative;
}

.queue-cover img{
    width100%;
    height100%;
    object-fit: cover;
}

.queue-cover i{
    position: absolute;
    top50%;
    left50%;
    transformtranslate(-50%, -50%);
    font-size30px;
    colorvar(--primary-color);
    display: none;
}

.queue.active i{
    display: block;
}

.queue .name{
    font-size22px;
    text-transform: capitalize;
}

输出

所有样式已经设置完成。也删除播放列表部分的active
类。

接下来就要JS出马了——使这个音乐app功能齐全。

导航

我们的音乐播放器中有三个部分。因此,为这个app设置导航系统非常重要,以方便我们从一个部分导航到另一个部分。代码如下:

/////////////////////navigations////////////

////////////toggling music player

const musicPlayerSection = document.querySelector('.music-player-section');

let clickCount = 1;

musicPlayerSection.addEventListener('click', () => {
    // checking for double click manually idk why default dbclick event was not working with this project If you know what could the problem Kindly tell me in the discussion below
    if(clickCount >= 2){
        musicPlayerSection.classList.add('active');
        clickCount = 1;
        return;
    }
    clickCount++;
    setTimeout(() => {
        clickCount = 1;
    }, 250);
})

/////// back from music player

const backToHomeBtn = document.querySelector('.music-player-section .back-btn');

backToHomeBtn.addEventListener('click', () => {
    musicPlayerSection.classList.remove('active');
})

//////// access playlist

const playlistSection = document.querySelector('.playlist');
const navBtn = document.querySelector('.music-player-section .nav-btn');

navBtn.addEventListener('click', () => {
    playlistSection.classList.add('active');
})

////////// back from playlist to music player

const backToMusicPlayer = document.querySelector('.playlist .back-btn');

backToMusicPlayer.addEventListener('click', () => {
    playlistSection.classList.remove('active');
})

//////navigation done ////////////////

这些都是基本的JS,并且我还在代码中添加了注释。完成了导航之后,我们就可以正式创建音乐播放器了。

音乐

对于音乐播放器,我们在页面中需要一个音频源,但现在我们没有。为此我们在index.html
中创建一个audio
元素。在body
标记的开头创建此元素。

<audio src="" id="audio-source"></audio>

现在我们必须创建很多函数,所以在开始之前快速选择我们可能需要进行操作的所有元素。

/////// music

let currentMusic = 0;

const music = document.querySelector('#audio-source');

const seekBar = document.querySelector('.music-seek-bar');
const songName = document.querySelector('.current-song-name');
const artistName = document.querySelector('.artist-name');
const coverImage = document.querySelector('.cover');
const currentMusicTime = document.querySelector('.current-time');
const musicDuration = document.querySelector('.duration');

const queue = [...document.querySelectorAll('.queue')];

// select all buttons here

const forwardBtn = document.querySelector('i.fa-forward');
const backwardBtn = document.querySelector('i.fa-backward');
const playBtn = document.querySelector('i.fa-play');
const pauseBtn = document.querySelector('i.fa-pause');
const repeatBtn = document.querySelector('span.fa-redo');
const volumeBtn = document.querySelector('span.fa-volume-up');
const volumeSlider = document.querySelector('.volume-slider');

下面设置音乐源。

// funtion for setting up music

const setMusic = (i) => {
    seekBar.value = 0;
    let song = songs[i];
    currentMusic = i;

    music.src = song.path;

    songName.innerHTML = song.name;
    artistName.innerHTML = song.artist;
    coverImage.src = song.cover;

    setTimeout(() => {
        seekBar.max = music.duration;
        musicDuration.innerHTML = formatTime(music.duration);
    }, 300);
    currentMusicTime.innerHTML = '00 : 00';
    queue.forEach(item => item.classList.remove('active'));
    queue[currentMusic].classList.add('active');
}

setMusic(0);

不知道你发现了没有,为了设置持续时间,我们调用了formatTime
。所以现在需要创建这个函数。

// format duration in 00 : 00 format

const formatTime = (time) => {
    let min = Math.floor(time / 60);
    if(min < 10){
        min = `0` + min;
    }

    let sec = Math.floor(time % 60);
    if(sec < 10){
        sec = `0` + sec;
    }

    return `${min} : ${sec}`;
}

接下来让我们添加播放/暂停事件。

// playBtn click event

playBtn.addEventListener('click', () => {
    music.play();
    playBtn.classList.remove('active');
    pauseBtn.classList.add('active');
})


// pauseBtn click event

pauseBtn.addEventListener('click', () => {
    music.pause();
    pauseBtn.classList.remove('active');
    playBtn.classList.add('active');
})

设置完了之后是前进/后退事件。

//  forward btn

forwardBtn.addEventListener('click', () => {
    if(currentMusic >= songs.length - 1){
        currentMusic = 0;
    } else{
        currentMusic++;
    }
    setMusic(currentMusic);
    playBtn.click();
})

// backward btn

backwardBtn.addEventListener('click', () => {
    if(currentMusic <= 0){
        currentMusic = songs.length - 1;
    } else{
        currentMusic--;
    }
    setMusic(currentMusic);
    playBtn.click();
})

快完工了哦,现在创建搜索栏功能。

// seekbar events

setInterval(() => {
    seekBar.value = music.currentTime;
    currentMusicTime.innerHTML = formatTime(music.currentTime);
    if(Math.floor(music.currentTime) == Math.floor(seekBar.max)){
        if(repeatBtn.className.includes('active')){
            setMusic(currentMusic);
            playBtn.click();
        } else{
            forwardBtn.click();
        }
    }
}, 500)

seekBar.addEventListener('change', () => {
    music.currentTime = seekBar.value;
})

创建重播功能和音量选项。

// repeat button

repeatBtn.addEventListener('click', () => {
    repeatBtn.classList.toggle('active');
})

// volume section

volumeBtn.addEventListener('click', () => {
    volumeBtn.classList.toggle('active');
    volumeSlider.classList.toggle('active');
})

volumeSlider.addEventListener('input', () => {
    music.volume = volumeSlider.value;
})

播放器完成!撒花!我们要做的最后一件事是使播放列表能够正常运行。

queue.forEach((item, i) => {
    item.addEventListener('click', () => {
        setMusic(i);
        playBtn.click();
    })
})

就是这样。我们完成了播放器、导航、播放列表、封面轮播。完美!

感谢阅读!如果你觉得文章写的对你有帮助的话,也欢迎分享给你的朋友!

每日分享前端插件干货,欢迎关注!

点赞和在看就是最大的支持❤️

文章转载自前端新世界,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论