پرس و جو برای کنترل بازیکن
پخش کننده سفارشی بدون کنترل های سفارشی چیست؟ گام بعدی این است که تمام کنترلهای سفارشی را که در HTML اضافه کردهایم پرس و جو کنید. ما از Document.querySelector()
روشی برای برگرداندن هر عنصر مرتبط اختصاص داده شده توسط یک متغیر.
// Player controls and attributes const playButton = document.querySelector(".player-play-btn") const playIcon = playButton.querySelector(".player-icon-play") const pauseIcon = playButton.querySelector(".player-icon-pause") const progress = document.querySelector(".player-progress") const progressFilled = document.querySelector(".player-progress-filled") const playerCurrentTime = document.querySelector(".player-time-current") const playerDuration = document.querySelector(".player-time-duration") const volumeControl = document.querySelector(".player-volume")
در اینجا ما متغیرهایی برای هر کنترل مستقل و نوار پیشرفت نشان داده شده در رابط کاربری داریم.
انتظار قبل از آتش گرفتن جاوا اسکریپت
برای بارگیری صحیح صدا، که گاهی اوقات ممکن است بیشتر از سایر موارد در صفحه طول بکشد، احتمالاً منطقی است که قبل از اجرای جاوا اسکریپت منتظر بارگیری کل صفحه باشیم.
ما با شنونده رویدادی شروع می کنیم که منتظر بارگذاری صفحه است. ما می توانیم کل کد خود را در این بلوک قرار دهیم.
window.addEventListener("load", () => { // all code goes here besides variables })
ما با گوش دادن به آن شروع می کنیم playButton
رویداد کلیک متغیر برای دستور دادن به پخش کننده ما بازی.
// Play button toggle playButton.addEventListener("click", () => { // check if context is in suspended state (autoplay policy) // By default, browsers won't allow you to autoplay audio. // You can override by finding the AudioContext state and resuming it after a user interaction like a "click" event. if (audioCtx.state === "suspended") { audioCtx.resume() } // Play or pause track depending on state if (playButton.dataset.playing === "false") { audioElement.play() playButton.dataset.playing = "true" playIcon.classList.add("hidden") pauseIcon.classList.remove("hidden") } else if (playButton.dataset.playing === "true") { audioElement.pause() playButton.dataset.playing = "false" pauseIcon.classList.add("hidden") playIcon.classList.remove("hidden") } })
چند چیز در یک زمان اتفاق می افتد زمانی که playButton
کلیک می شود
- مرورگرها به اندازه کافی هوشمند هستند که پخش خودکار صدا را در اولین بارگذاری متوقف کنند. درون
AudioContext
متد، یک متد حالت وجود دارد که مقدار «معلق»، «در حال اجرا» یا «بسته» را برمیگرداند. در مورد ما، ما به دنبال “تعلیق” خواهیم بود. اگر این حالتی است که برمیگردد، میتوانیم با متد فراخوانی صدا را از سر بگیریمresume()
. -
ما از ویژگی های داده در HTML استفاده می کنیم تا مشخص کنیم که دکمه در حال پخش یا توقف است.
-
اگر دکمه پخش یا مکث کلیک شود، می توانیم به صورت پویا بگوییم
audioElement
به بازی یا مکث. -
برای تجربه کاربری بهتر، من قابلیت نمایش و پنهان کردن آیکون های پخش یا مکث را بسته به وضعیت پخش کننده اضافه کردم.
به روز رسانی تمبر زمان و پیشرفت
هر آهنگی که با یک زمینه AudioElement بارگیری می کنید ویژگی ها و ابرداده های خود را دارد که می توانید در HTML نمایش دهید. ما با صفر کردن همه چیز در بارگذاری صفحه اول شروع می کنیم و به فراخوانی تابعی ادامه می دهیم که به صورت پویا زمان پخش یا توقف صدا را به روز می کند و فرمت می کند.
علاوه بر این، نوار پیشرفتی را نشان خواهیم داد که به صورت پویا بر اساس میزان صدای رد شده پر می شود. این برای کاربر نهایی مفید است که ممکن است بخواهد به جای خواندن زمان باقی مانده، به نوار پیشرفت نگاه کند.
// Update progress bar and time values as audio plays audioElement.addEventListener("timeupdate", () => { progressUpdate() setTimes() })
من دو تابع ایجاد کردم که در جای دیگری از فایل جاوا اسکریپت استخراج می شوند. نکته اصلی در مورد کد بالا، نوع شنونده رویدادی است که ما آن را پیگیری می کنیم. این timeupdate
رویداد منحصر به فرد برای رسانه هایی مانند صدا یا تصویر در Web API است.
زمان نمایش و قالب بندی
ما می توانیم استفاده کنیم playerCurrentTime
و playerDuration
متغیرها برای نمایش و فرمت زمان محتوای متن آن برچسبها را در HTML تنظیم میکنیم تا با یک مهر زمانی جدید نسبت به ویژگیهای فعلی عنصر audio مطابقت داشته باشد. یک audioElement دارای یک است currentTime
اموال و الف duration
ویژگی.
با استفاده از Date API در جاوا اسکریپت، میتوانیم برای تبدیل ثانیههای پیشفرض که از آن برگردانده میشوند، روی یک خط یک خطی استفاده کنیم. currentTime
و duration
در قالبی که مطابقت دارد HH:MM:SS
(ساعت، دقیقه، ثانیه).
// Display currentTime and duration properties in real-time function setTimes() { playerCurrentTime.textContent = new Date(audioElement.currentTime * 1000) .toISOString() .substr(11, 8) playerDuration.textContent = new Date(audioElement.duration * 1000) .toISOString() .substr(11, 8) }
به روز رسانی پیشرفت بازیکن
به روز رسانی نوار پیشرفت در HTML ما نسبتاً ساده است و به محاسبه درصد می رسد. درصد برگشتی را با تقسیم درصد بدست می آوریم audioElement.currentTime
توسط audioElement.duration
و آن را در 100 ضرب کنیم.
در نهایت، میتوانیم مقداری CSS از طریق جاوا اسکریپت با استفاده از آن تنظیم کنیم progressFilled
متغیری که قبلا ایجاد کردیم و آن را تنظیم کردیم flex-basis
بسته به درصد تغییر، خاصیت رشد یا کوچک شدن دارد.
// Update player timeline progress visually function progressUpdate() { const percent = (audioElement.currentTime / audioElement.duration) * 100 progressFilled.style.flexBasis = `${percent}%` }
افزودن کنترل های صدا
تنظیم صدا به شیء AudioContext که قبلاً استفاده می کردیم باز می گردد. ما باید متدی را به نام فراخوانی کنیم createGain()
و مقدار افزایش را به نگاشت به ورودی محدوده حجم در HTML تغییر دهید.
// Bridge the gap between gainNode and AudioContext so we can manipulate volume (gain) const gainNode = audioCtx.createGain() volumeControl.addEventListener("change", () => { gainNode.gain.value = volumeControl.value }) track.connect(gainNode).connect(audioCtx.destination)
یک را ایجاد کردیم track
متغیر در ابتدای این آموزش است و در نهایت آن را برای استفاده در اینجا قرار می دهیم. با استفاده از connect()
روش، شما می توانید اتصال مسیر به gainNode
و سپس به AudioContext
. بدون این خط، ورودی محدوده حجم صدا از میزان صدا اطلاعی ندارد.
ما برای یک گوش خواهیم داد تغییر دادن رویداد برای ترسیم حجم نسبت به بهره.
وقتی صدا به پایان می رسد چه اتفاقی می افتد؟
ما میتوانیم پخشکننده را پس از پایان صدا بازنشانی کنیم تا در صورتی که کاربر نهایی بخواهد آن را دوباره شروع کند، برای گوش دادن دیگر آماده شود.
// if the track ends, reset the player audioElement.addEventListener("ended", () => { playButton.dataset.playing = "false" pauseIcon.classList.add("hidden") playIcon.classList.remove("hidden") progressFilled.style.flexBasis = "0%" audioElement.currentTime = 0 audioElement.duration = audioElement.duration })
در اینجا ما نماد دکمه پخش را تغییر می دهیم مکث به بازی، ویژگی پخش داده را روی آن تنظیم کنید false
، نوار پیشرفت و audioElement را بازنشانی کنید currentTime
و duration
خواص
نوار پیشرفت را برای پرش و عقب کشیدن تمیز کنید
نوار پیشرفت ما از نظر بصری کاربردی است، اما اگر بتوانید در هر نقطه از جدول زمانی کلیک کنید و پخش صدای فعلی را تنظیم کنید، مفیدتر خواهد بود. ما می توانیم با یک سری شنونده رویداد و یک عملکرد جدید به این مهم دست یابیم.
// Scrub player timeline to skip forward and back on click for easier UX let mousedown = false function scrub(event) { const scrubTime = (event.offsetX / progress.offsetWidth) * audioElement.duration audioElement.currentTime = scrubTime } progress.addEventListener("click", scrub) progress.addEventListener("mousemove", (e) => mousedown && scrub(e)) progress.addEventListener("mousedown", () => (mousedown = true)) progress.addEventListener("mouseup", () => (mousedown = false))
این scrub()
تابع نیاز به آرگومان رویدادی دارد که ما به آن گوش می دهیم. به طور خاص، offsetX
ویژگی به ما این امکان را می دهد که مشخص کنیم کاربر کجا کلیک کرده است و محاسباتی را نسبت به ویژگی های audioElement انجام دهیم.
در نهایت، میتوانیم برای مجموعهای از رویدادها به نوار پیشرفت گوش دهیم کلیک، حرکت ماوس، ماوس پایین، و موس برای تنظیم عنصر صوتی currentTime
ویژگی.
4. همه اش را بگذار کنار هم
کد نهایی جاوا اسکریپت در زیر آمده است. نکته ای که باید به آن توجه داشت در بارگذاری صفحه اول است. من به setTimes()
یک بار دیگر این کار را انجام دهید تا بتوانیم قبل از اینکه کاربر شروع به دستکاری پخش کننده صوتی کند، زمان واقعی به درستی نمایش داده شود.
// load sound via <audio> tag const audioElement = document.querySelector("audio") const audioCtx = new AudioContext() const track = audioCtx.createMediaElementSource(audioElement) // Player controls and attributes const playButton = document.querySelector(".player-play-btn") const playIcon = playButton.querySelector(".player-icon-play") const pauseIcon = playButton.querySelector(".player-icon-pause") const progress = document.querySelector(".player-progress") const progressFilled = document.querySelector(".player-progress-filled") const playerCurrentTime = document.querySelector(".player-time-current") const playerDuration = document.querySelector(".player-time-duration") const volumeControl = document.querySelector(".player-volume") document.addEventListener("DOMContentLoaded", () => { // Set times after page load setTimes() // Update progress bar and time values as audio plays audioElement.addEventListener("timeupdate", () => { progressUpdate() setTimes() }) // Play button toggle playButton.addEventListener("click", () => { // check if context is in suspended state (autoplay policy) // By default, browsers won't allow you to autoplay audio. // You can override by finding the AudioContext state and resuming it after a user interaction like a "click" event. if (audioCtx.state === "suspended") { audioCtx.resume() } // Play or pause track depending on state if (playButton.dataset.playing === "false") { audioElement.play() playButton.dataset.playing = "true" playIcon.classList.add("hidden") pauseIcon.classList.remove("hidden") } else if (playButton.dataset.playing === "true") { audioElement.pause() playButton.dataset.playing = "false" pauseIcon.classList.add("hidden") playIcon.classList.remove("hidden") } }) // if the track ends, reset the player audioElement.addEventListener("ended", () => { playButton.dataset.playing = "false" pauseIcon.classList.add("hidden") playIcon.classList.remove("hidden") progressFilled.style.flexBasis = "0%" audioElement.currentTime = 0 audioElement.duration = audioElement.duration }) // Bridge the gap between gainNode and AudioContext so we can manipulate volume (gain) const gainNode = audioCtx.createGain() const volumeControl = document.querySelector(".player-volume") volumeControl.addEventListener("change", () => { gainNode.gain.value = volumeControl.value }) track.connect(gainNode).connect(audioCtx.destination) // Display currentTime and duration properties in real-time function setTimes() { playerCurrentTime.textContent = new Date(audioElement.currentTime * 1000) .toISOString() .substr(11, 8) playerDuration.textContent = new Date(audioElement.duration * 1000) .toISOString() .substr(11, 8) } // Update player timeline progress visually function progressUpdate() { const percent = (audioElement.currentTime / audioElement.duration) * 100 progressFilled.style.flexBasis = `${percent}%` } // Scrub player timeline to skip forward and back on click for easier UX let mousedown = false function scrub(event) { const scrubTime = (event.offsetX / progress.offsetWidth) * audioElement.duration audioElement.currentTime = scrubTime } progress.addEventListener("click", scrub) progress.addEventListener("mousemove", (e) => mousedown && scrub(e)) progress.addEventListener("mousedown", () => (mousedown = true)) progress.addEventListener("mouseup", () => (mousedown = false)) // Track credit: Outfoxing the Fox by Kevin MacLeod under Creative Commons + MDN for the link. })
نتیجه
شما آن را دارید! با کمی جاوا اسکریپت و گریس آرنج، میتوانید پخشکننده موسیقی برند خود را بسازید.
از اینجا، میتوانید با افزودن کنترلهای بیشتر، مانند پرش دکمهها یا دکمههای متحرک، آزمایش کنید. من همچنین می خواهم بررسی کنید AudioTracklist رابط، که به شما امکان می دهد لیست های پخش ایجاد کنید و طراحی را در صورت لزوم گسترش دهید.