برای ساخت این پروژه از تگ audio استفاده می کنیم. اطلاعات بیش تر در مورد این تگ در این نشانی آمده است. تصویر کامل برنامه در زیر آمده است:
برای ساخت این پروژه به دو پوشه به نام های music و images و فایل های index.html، style.css و script.js نیاز داریم.
پوشه images برای نگهداری تصاویر است.این تصاویر برای عکس کاور آهنگ هستند. پوشه music دربردارنده لیست موزیک ها است. هر تعداد موزیک که بخواهیم می توانیم در این پوشه بگذاریم. برنامه آهنگ های موجود در این پوشه را پخش می کند.
فایل index.html برای تعیین ساختار برنامه است. در این فایل عناصر مختلف خود مانند تگ body و... را تعریف می کنیم. فایل های style.css و script.js در این فایل قرار می گیرند. style.css در تگ head و script.js در انتهای تگ body قرار می گیرد.
style.css برای استایل دهی و script.js برای پیاده سازی منطق برنامه به کار می رود. تک تک فایل ها را در زیر توضیح می دهیم و به نحو پیاده سازی آن ها می پردازیم.
همان طور که قبلا هم گفتم این فایل برای تعیین ساختار برنامه و شکل کلی آن است. کد آن در زیر آمده است:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.2/css/all.min.css" /> <link rel="stylesheet" href="style.css" /> <title>Music Player</title> </head> <body> <h1>Music Player</h1> <div class="music-container" id="music-container"> <div class="music-info"> <h4 id="title"></h4> <div class="progress-container" id="progress-container"> <div class="progress" id="progress"></div> </div> </div> <audio src="music/ukulele.mp3" id="audio"></audio> <div class="img-container"> <img src="images/ukulele.jpg" alt="music-cover" id="cover" /> </div> <div class="navigation"> <button id="prev" class="action-btn"> <i class="fas fa-backward"></i> </button> <button id="play" class="action-btn action-btn-big"> <i class="fas fa-play"></i> </button> <button id="next" class="action-btn"> <i class="fas fa-forward"></i> </button> </div> </div> <script src="script.js"></script> </body> </html>
برای استفاده از آیکون ها و زیباتر سازی برنامه از fontawesome استفاده می کنیم:
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.2/css/all.min.css" />
در ادامه به یک نگهدارنده یا کانتینر اصلی نیاز داریم. این نگهدارنده یک تگ div با کلاس music-container است.
اجزای اصلی برنامه در این قسمت قرار می گیرند و همان طور که قبلا هم گفتیم این تگ یک نگهدارنده است. به چندین تگ دیگر نیز نیاز داریم. این تگ ها در زیر آمده اند:
<div class="music-info"> <h4 id="title"></h4> <div class="progress-container" id="progress-container"> <div class="progress" id="progress"></div> </div> </div>
<audio src="music/ukulele.mp3" id="audio"></audio>
<div class="img-container"> <img src="images/ukulele.jpg" alt="music-cover" id="cover" /> </div>
<div class="navigation"> <button id="prev" class="action-btn"> <i class="fas fa-backward"></i> </button> <button id="play" class="action-btn action-btn-big"> <i class="fas fa-play"></i> </button> <button id="next" class="action-btn"> <i class="fas fa-forward"></i> </button> </div>
برای درک بهتر به تصویر زیر نگاه کنید:
اگر فایل index.html را در مرورگز باز کنیم باید تصویر زیر را ببینیم:
این فایل بدون استایل است.گام بعدی افزودن استایل یا همان استفاده از css است.
این برای زیبا سازی و استایل دهی به برنامه است. کد آن در زیر آمده است:
@import url('https://fonts.googleapis.com/css?family=Lato&display=swap'); * { box-sizing: border-box; } body { background-image: linear-gradient( 0deg, rgba(247, 247, 247, 1) 23.8%, rgba(252, 221, 221, 1) 92% ); height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; font-family: 'Lato', sans-serif; margin: 0; } .music-container { background-color: #fff; border-radius: 15px; box-shadow: 0 20px 20px 0 rgba(252, 169, 169, 0.6); display: flex; padding: 20px 30px; position: relative; margin: 100px 0; z-index: 10; } .img-container { position: relative; width: 110px; } .img-container::after { content: ''; background-color: #fff; border-radius: 50%; position: absolute; bottom: 100%; left: 50%; width: 20px; height: 20px; transform: translate(-50%, 50%); } .img-container img { border-radius: 50%; object-fit: cover; height: 110px; width: inherit; position: absolute; bottom: 0; left: 0; animation: rotate 3s linear infinite; animation-play-state: paused; } .music-container.play .img-container img { animation-play-state: running; } @keyframes rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } .navigation { display: flex; align-items: center; justify-content: center; z-index: 1; } .action-btn { background-color: #fff; border: 0; color: #dfdbdf; font-size: 20px; cursor: pointer; padding: 10px; margin: 0 20px; } .action-btn.action-btn-big { color: #cdc2d0; font-size: 30px; } .action-btn:focus { outline: 0; } .music-info { background-color: rgba(255, 255, 255, 0.5); border-radius: 15px 15px 0 0; position: absolute; top: 0; left: 20px; width: calc(100% - 40px); padding: 10px 10px 10px 150px; opacity: 0; transform: translateY(0%); transition: transform 0.3s ease-in, opacity 0.3s ease-in; z-index: 0; } .music-container.play .music-info { opacity: 1; transform: translateY(-100%); } .music-info h4 { margin: 0; } .progress-container { background: #fff; border-radius: 5px; cursor: pointer; margin: 10px 0; height: 4px; width: 100%; } .progress { background-color: #fe8daa; border-radius: 5px; height: 100%; width: 0%; transition: width 0.1s linear; }
در بالا برای المنت های خود استایل موردنظر را تعریف می کنیم. وقتی که آهنگ پخش می شود دوست داریم که تصویر کاور بچرخد. برای این کار باید از انیمیشن ها استفاده کنیم. برای انیمیشن باید یک نام تعریف کنیم و سپس keyframes آن را قابل اجرا کنیم. وضعیت انیمیشن paused یعنی متوقف شده است.
.img-container img { border-radius: 50%; object-fit: cover; height: 110px; width: inherit; position: absolute; bottom: 0; left: 0; animation: rotate 3s linear infinite; animation-play-state: paused; }
اگر تصویر یا نگهدارنده آن یعنی img-container دارای کلاس play باشد می خواهیم وضعیت انیمیشن به حالت اجرا یا running در بیاید.
.music-container.play .img-container img { animation-play-state: running; } @keyframes rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
چون می خواهیم تصویر یک چرخش کامل داشته باشد یا از صفر تا 360 درجه زاویه چرخش آن تغییر کند. هم چنین می خواهیم وقتی آهنگ پخش می شود کانتینر اطلاعات آهنگ به سمت بالا می آید و نمایش داده شود. پس تا هنگامی که آهنگ پخش نشده است نباید نمایش داده شود پس باید translateY باید صفر درصد باشد. transition به شما این امکان را می دهد که مقادیر property ها را به تدریج، در مدت زمان معینی تغییر دهید.
.music-info { background-color: rgba(255, 255, 255, 0.5); border-radius: 15px 15px 0 0; position: absolute; top: 0; left: 20px; width: calc(100% - 40px); padding: 10px 10px 10px 150px; opacity: 0; transform: translateY(0%); transition: transform 0.3s ease-in, opacity 0.3s ease-in; z-index: 0; }
اما اگر آهنگ پخش شد باید اطلاعات نمایش داده شود پس translateY باید 100%- شود.
.music-container.play .music-info { opacity: 1; transform: translateY(-100%); }
برای نشان دادن مدت زمان آهنگ از یک تگ div با کلاس progress-container استفاده می کنیم که در music-info تعریف شده است. برای نشان دادن اجرا شدن آهنگ و گذشتن زمان در css از کد زیر استفاده می کنیم:
.progress { background-color: #fe8daa; border-radius: 5px; height: 100%; width: 0%; transition: width 0.1s linear; }
اگر برنامه را اجرا کنیم باید تصویر زیر را ببینیم:
اگر دکمه ها را فشار دهیم هیچ اتفاقی نمی افتد. برای کار کردن این برنامه به جاوااسکریپت نیاز داریم. پس بیایید آن را بسازیم.
این فایل مغز برنامه است. کد آن در زیر آمده است:
const musicContainer = document.getElementById('music-container'); const playBtn = document.getElementById('play'); const prevBtn = document.getElementById('prev'); const nextBtn = document.getElementById('next'); const audio = document.getElementById('audio'); const progress = document.getElementById('progress'); const progressContainer = document.getElementById('progress-container'); const title = document.getElementById('title'); const cover = document.getElementById('cover'); // Song titles const songs = ['hey', 'summer', 'ukulele']; // Keep track of song let songIndex = 2; // Initially load song details into DOM loadSong(songs[songIndex]); // Update song details function loadSong(song) { title.innerText = song; audio.src = `music/${song}.mp3`; cover.src = `images/${song}.jpg`; } // Play song function playSong() { musicContainer.classList.add('play'); playBtn.querySelector('i.fas').classList.remove('fa-play'); playBtn.querySelector('i.fas').classList.add('fa-pause'); audio.play(); } // Pause song function pauseSong() { musicContainer.classList.remove('play'); playBtn.querySelector('i.fas').classList.add('fa-play'); playBtn.querySelector('i.fas').classList.remove('fa-pause'); audio.pause(); } // Previous song function prevSong() { songIndex--; if (songIndex < 0) { songIndex = songs.length - 1; } loadSong(songs[songIndex]); playSong(); } // Next song function nextSong() { songIndex++; if (songIndex > songs.length - 1) { songIndex = 0; } loadSong(songs[songIndex]); playSong(); } // Update progress bar function updateProgress(e) { const { duration, currentTime } = e.srcElement; const progressPercent = (currentTime / duration) * 100; progress.style.width = `${progressPercent}%`; } // Set progress bar function setProgress(e) { const width = this.clientWidth; const clickX = e.offsetX; const duration = audio.duration; audio.currentTime = (clickX / width) * duration; } // Event listeners playBtn.addEventListener('click', () => { const isPlaying = musicContainer.classList.contains('play'); if (isPlaying) { pauseSong(); } else { playSong(); } }); // Change song prevBtn.addEventListener('click', prevSong); nextBtn.addEventListener('click', nextSong); // Time/song update audio.addEventListener('timeupdate', updateProgress); // Click on progress bar progressContainer.addEventListener('click', setProgress); // Song ends audio.addEventListener('ended', nextSong);
سپس باید آهنگ ها را تعریف کنیم.نام آهنگ ها را در آرایه ای قرار می دهیم.
// Song titles const songs = ['hey', 'summer', 'ukulele'];
برای این که برنامه به درستی کار کند نام تصویرها باید با نام آهنگ ها یکسان باشد. برای ردیابی و در واقع دستیابی به آن ها باید از یک اندیس استفاده کنیم.
// Keep track of song let songIndex = 2;
حالا باید آهنگ ها را واکشی کنیم و در فایل javascript خود قرار دهیم.
// Initially load song details into DOM loadSong(songs[songIndex]); // Update song details function loadSong(song) { title.innerText = song; audio.src = `music/${song}.mp3`; cover.src = `images/${song}.jpg`; }
تابع loadSong برای واکشی ها و قرار دادن آن ها در DOM است. این تابع نام آهنگ، مکان آهنگ و مکان تصویر آن را تنظیم می کند. می خواهیم وقتی روی دکمه play کلیک می کنیم آهنگ پخش شود. برای این کار یک شنونده رویداد به این دکمه می افزاییم.
// Event listeners playBtn.addEventListener('click', () => { const isPlaying = musicContainer.classList.contains('play'); if (isPlaying) { pauseSong(); } else { playSong(); } });
اگر کانتینر دارای کلاس play باشد یعنی آهنگ باید اجرا شود. این تابع این شرط را بررسی می کند و در صورت برقرار بودن شرط تابع pauseSong و در غیر این صورت تابع playSong را اجرا می کنیم.
کد تابع pauseSong در زیر آمده است:
// Pause song function pauseSong() { musicContainer.classList.remove('play'); playBtn.querySelector('i.fas').classList.add('fa-play'); playBtn.querySelector('i.fas').classList.remove('fa-pause'); audio.pause(); }
کد تابع playSong در زیر آمده است:
// Play song function playSong() { musicContainer.classList.add('play'); playBtn.querySelector('i.fas').classList.remove('fa-play'); playBtn.querySelector('i.fas').classList.add('fa-pause'); audio.play(); }
با audio.play آهنگ پخش و با audio.pause آهنگ متوقف می شود. برای این که بتوانیم آهنگ را تغییر بدهیم و آهنگ بعدی یا قبلی برویم باید برای دکمه های next و pre شنونده رویداد ایجاد کنیم.
// Change song prevBtn.addEventListener('click', prevSong); nextBtn.addEventListener('click', nextSong);
تابع prevSong برای پخش آهنگ قبلی است. آهنگ قبلی یک خانه یا یک اندیس با آهنگی که در حال پخش است تفاوت دارد. پس اندیس باید یک واحد کم شود. اگر این کم کردن باعث منفی شدن اندیس شود آخرین آهنگ پخش خواهد شد.کد آن در زیر آمده است:
// Previous song function prevSong() { songIndex--; if (songIndex < 0) { songIndex = songs.length - 1; } loadSong(songs[songIndex]); playSong(); }
تابع nextSong برای پخش آهنگ بعدی است. آهنگ بعدی یک خانه یا یک اندیس با آهنگی که در حال پخش است تفاوت دارد. پس اندیس باید یک اضافه شود. اگر اندازه اندیس از اندازه آرایه بیش تر شود اولین آهنگ پخش خواهد شد. کد آن در زیر آمده است:
// Next song function nextSong() { songIndex++; if (songIndex > songs.length - 1) { songIndex = 0; } loadSong(songs[songIndex]); playSong(); }
در ادامه دوست داریم با پخش شدن آهنگ و گذشت زمان نوار progress به روز آوری شود و پر شود. برای این کار داریم:
// Time/song update audio.addEventListener('timeupdate', updateProgress);
برای پرشدن نوار progress تابع updateProgress را تعریف می کنیم:
// Update progress bar function updateProgress(e) { const { duration, currentTime } = e.srcElement; const progressPercent = (currentTime / duration) * 100; progress.style.width = `${progressPercent}%`; }
طول زمانی آهنگ و زمان کنونی پخش آن را می توان از srcElement به دست آورد. از این اعداد برای محاسبه درصد پرشدن نوار progress استفاده می کنیم.درصد به دست آمده را در متغیر progressPercent قرار می دهیم. این عدد with یا طول نوار progress را مشخص می کند.
در ادامه می خواهیم با کلیک کردن روی نوار progress، آهنگ به جایی که کلیک کرده ایم برود و از آن جا پخش شود و هم چنین نوار تا آن جا رنگی شود. برای این کار یک شنونده رویداد به متغیر progressContainer اضافه می کنیم.
// Click on progress bar progressContainer.addEventListener('click', setProgress);
با کلیک کردن بر روی نوار progress تابع setProgress اجرا می شود. کد این تابع در زیر آمده است:
// Set progress bar function setProgress(e) { const width = this.clientWidth; const clickX = e.offsetX; const duration = audio.duration; audio.currentTime = (clickX / width) * duration; }
به جایی که موس کلیک می شود نیاز داریم.جایی که موس کلیک می شود را در متغیر clickX قرار می دهیم. در آخر می خواهیم وقتی یک آهنگ تمام می شود، آهنگ بعدی پخش شود.
// Song ends audio.addEventListener('ended', nextSong);
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.