๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Effect/Game Effect

[Game Effect] ๊ฒŒ์ž„ ์ดํŽ™ํŠธ 01 - ๋ฎค์ง ํ”Œ๋ ˆ์ด์–ด

by ์ฝ”๋”ฉ๊ณต์ฑ… 2022. 10. 21.
๋ฐ˜์‘ํ˜•

๊ฒŒ์ž„ ์ดํŽ™ํŠธ 01

์ด๋ฒˆ ์‹œ๊ฐ„์—๋Š” ๊ทธ ๋™์•ˆ ๋ฐฐ์› ๋˜ JavaScript๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ฒŒ์ž„ ์ดํŽ™ํŠธ๋ฅผ ๋งŒ๋“ค์–ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
์ปดํ“จํ„ฐ ๋ฐ”ํƒ•ํ™”๋ฉด๊ณผ ์ž‘๋™๋˜๋Š” ๋ฎค์ง ํ”Œ๋ ˆ์ด์–ด๋ฅผ ๋งŒ๋“ค์–ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.


HTML ์†Œ์Šค ๋ณด๊ธฐ

HTML ๊ตฌ์„ฑ์€ ํ—ค๋”(์ œ๋ชฉ, ์‹œ๊ฐ„)์™€ ๋ฉ”์ธ(๋ฐ”ํƒ•ํ™”๋ฉด ์•„์ด์ฝ˜), ํ‘ธํ„ฐ(agent, ์†Œ์Šค ๋ณด๊ธฐ), ๋ฎค์ง ํ”Œ๋ ˆ์ด์–ด๋กœ ๊ตฌ์„ฑ๋œ๋‹ค.

<body>
    <div class="mouse__cursor"></div>
    <!-- png ํ˜•์‹์œผ๋กœ ๋งˆ์šฐ์Šค ์ปค์„œ๋ฅผ ์ ์šฉํ•  ๋•Œ์— ํ•„์š”ํ•จ, cur ํŒŒ์ผ ์ ์šฉ์˜ ๊ฒฝ์šฐ ๋ถˆํ•„์š” -->

    <header id="header">
        <h1>Coding Note's Game World</h1>
        <div class="time"></div>
    </header>
    <!-- // header -->

    <main id="main">
        <div class="icon_box">
            <div class="icon0">
                <img src="../assets/img/icon0.png" alt="๋””์Šคํฌ">
                <span>๋””์Šคํฌ</span>
            </div>
            <div class="icon1">
                <img src="../assets/img/icon1.png" alt="๋ฎค์ง">
                <span>๋ฎค์ง ๋“ฃ๊ธฐ</span>
            </div>
            <div class="icon2">
                <img src="../assets/img/icon2.png" alt="์ƒต ํด๋”">
                <span>์ƒต ํด๋”</span>
            </div>
            <div class="icon3">
                <img src="../assets/img/icon3.png" alt="๋™์˜์ƒ">
                <span>๋™์˜์ƒ</span>
            </div>
            <div class="icon4">
                <img src="../assets/img/icon4.png" alt="ํŒŒ์ผ">
                <span>ํŒŒ์ผ</span>
            </div>
            <div class="icon5">
                <img src="../assets/img/icon5.png" alt="FIGMA">
                <span>FIGMA</span>
            </div>
        </div>
    </main>
    <!-- // main -->

    <footer id="footer">
        <div class="agent">agent</div>
        <div class="modal__wrap">
            <div class="modal__btn">
                <label for="btn">์†Œ์Šค ๋ณด๊ธฐ</label>
            </div>
            <div class="modal__cont">
                <div class="modal__close">
                    <span class="close">
                        <svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false">
                            <path d="M12.5 3.5L3.5 12.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path>
                            <path d="M12.5 12.5L3.5 3.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path>
                        </svg>
                    </span>
                </div>
                <div class="t_iframe">
                    <iframe src="https://github1s.com/kde66034/coding" frameborder="0"></iframe>
                </div>
            </div>
        </div>
    </footer>
    <!-- // footer -->

    <!-- ๋ฎค์ง ํ”Œ๋ ˆ์ด์–ด -->
    <div class="music__wrap">
        <div class="music__inner">
            <div class="music__header">
                <div>***</div>
                <h2>MUSIC PLAYER</h2>
                <div>***</div>
            </div>
            <div class="music__contents">
                <div class="volume__wrap">
                    <img class="volume_icon" src="../assets/img/volume.svg" alt="๋ณผ๋ฅจ" />
                    <img class="volumeOff_icon" src="../assets/img/volumeoff.svg" alt="๋ณผ๋ฅจ" />
                    <div class="volume_bar">
                        <input type="range" id="volume-control" min="0" max="10" />
                    </div>
                </div>
                <div class="music__view">
                    <div class="img">
                        <img src="../assets/img/music-1.png" alt="">
                    </div>
                    <div class="title">
                        <h3>Kazoom - Quincas Moreira</h3>
                        <p>YouTube Music</p>
                    </div>
                </div>
                <div class="music__control">
                    <div class="progress">
                        <div class="bar">
                            <audio id="main-audio" src="../assets/audio/music-1.mp3"></audio>
                        </div>
                        <div class="timer">
                            <span class="current">0:00</span>
                            <span class="duration">4:00</span>
                        </div>
                    </div>
                    <div class="control">
                        <i title="์ „์ฒด ๋ฐ˜๋ณต" class="repeat" id="control-repeat"></i>
                        <!-- <i title="ํ•œ๊ณก ๋ฐ˜๋ณต" class="repeat_one"></i>
                        <i title="๋žœ๋ค ์žฌ์ƒ" class="shuffle"></i> -->
                        <i title="์ด์ „๊ณก ์žฌ์ƒ" class="prev" id="control-prev"></i>
                        <i title="์žฌ์ƒ" class="play" id="control-play"></i>
                        <i title="์ •์ง€" class="stop" id="control-stop"></i>
                        <i title="๋‹ค์Œ๊ณก ์žฌ์ƒ" class="next" id="control-next"></i>
                        <i title="์žฌ์ƒ๋ชฉ๋ก" class="list" id="control-list"></i>
                    </div>
                </div>
            </div>
            <div class="music__footer">
                <div class="music__list close">
                    <h3><span class="list">๋ฎค์ง ๋ฆฌ์ŠคํŠธ</span> <span class="close-btn" id="control-close"></span></h3>
                    <ul>
                        <!-- <li>
                            <strong>์ œ๋ชฉ</strong>
                            <em>์•„ํ‹ฐ์ŠคํŠธ</em>
                            <span>์žฌ์ƒ์‹œ๊ฐ„</span>
                        </li> -->
                    </ul>
                </div>
            </div>
        </div>
    </div>
</body>

JavaScript ์†Œ์Šค ๋ณด๊ธฐ : ํ—ค๋”(์ƒ๋‹จ๋ฐ”)์— ์‹œ๊ฐ„ ํ‘œ์‹œํ•˜๊ธฐ

์‹œ๊ฐ„, ๋‚ ์งœ๋ฅผ ์ €์žฅํ•  ์ƒ์ˆ˜์™€ ์‹œ, ๋ถ„, ์ดˆ๋ฅผ ์ €์žฅํ•  ๋ณ€์ˆ˜๋ฅผ ์ƒ์„ฑํ•œ ๋‹ค์Œ if๋ฌธ์„ ์ด์šฉํ•˜์—ฌ ์‹œ๊ฐ„์„ ๋‚˜ํƒ€๋‚ด๋Š” ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์งœ๋„๋ก ํ•œ๋‹ค.

function printTime(){
const clock = document.querySelector(".time");
const now = new Date();

let nowHours = now.getHours();
let nowMins = now.getMinutes();
let nowSecs = now.getSeconds();
if(nowHours > 12) {
    nowHours = `${nowHours - 12}`
} else if(nowHours >= 0 && nowHours<=9){
    nowHours = `0${nowHours}`
};
if(nowMins < 10) nowMins = `0${nowMins}`;
if(nowSecs < 10) nowSecs = `0${nowSecs}`;
let nowMonth = now.getMonth() + 1;
let nowDate = now.getDate();
if(nowMonth  < 10 ) nowMonth = `0${nowMonth}`
if(nowDate < 10 ) nowDate = `0${nowDate}`

const nowTime = `${now.getFullYear()}๋…„ ${(now.getMonth()+1)}์›” ${now.getDate()}์ผ ${nowHours}์‹œ ${nowMins}๋ถ„ ${nowSecs}์ดˆ`;

    clock.innerText = nowTime;
    setTimeout("printTime()", 1000);
}

JavaScript ์†Œ์Šค ๋ณด๊ธฐ : Agent

ํ•˜๋‹จ ํ‘ธํ„ฐ ์˜์—ญ์— ํ˜„์žฌ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ๊ธฐ๊ธฐ์™€ ํ™”๋ฉด ํฌ๊ธฐ๋ฅผ ํ‘œ์‹œ์‹œํ‚ค๊ธฐ ์œ„ํ•œ ์Šคํฌ๋ฆฝํŠธ์ด๋‹ค. agent, os๋ผ๋Š” ์ƒ์ˆ˜๋ฅผ ๋งŒ๋“ค๊ณ  agent ์˜์—ญ์— innerText๋กœ os ์ •๋ณด๋ฅผ ์ถœ๋ ฅ์‹œํ‚จ๋‹ค. if, else if๋ฌธ์„ ์ด์šฉํ•˜์—ฌ ๊ฐ๊ฐ ์šด์˜์ฒด์ œ๋ณ„๋กœ ์ถœ๋ ฅ์‹œํ‚ฌ ๋ฌธ๊ตฌ๋ฅผ ์Šคํฌ๋ฆฝํŠธ๋กœ ์ง ๋‹ค.

function printAgent() {
    const agent = document.querySelector(".agent");
    const os = navigator.userAgent.toLocaleLowerCase();

    agent.innerText = os;

    if(os.indexOf("window") >= 0){
        agent.innerText = "ํ˜„์žฌ Windows๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ํ™”๋ฉด ํฌ๊ธฐ๋Š” "+ screen.width +"x"+ screen.height + "์ž…๋‹ˆ๋‹ค.";
        document.querySelector("body").classList.add("window");
    } else if(os.indexOf("macintosh") >= 0){
        agent.innerText = "ํ˜„์žฌ Mac์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ํ™”๋ฉด ํฌ๊ธฐ๋Š” "+ screen.width +"x"+ screen.height + "์ž…๋‹ˆ๋‹ค.";
        document.querySelector("body").classList.add("mac");
    } else if(os.indexOf("iphone") >= 0){l
        agent.innerText = "ํ˜„์žฌ iPhone์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ํ™”๋ฉด ํฌ๊ธฐ๋Š” "+ screen.width +"x"+ screen.height + "์ž…๋‹ˆ๋‹ค.";
        document.querySelector("body").cassList.add("iphone");
    } else if(os.indexOf("android") >= 0){
        agent.innerText = "ํ˜„์žฌ Android๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ํ™”๋ฉด ํฌ๊ธฐ๋Š” "+ screen.width +"x"+ screen.height + "์ž…๋‹ˆ๋‹ค.";
        document.querySelector("body").classList.add("android");
    }
}

window.onload = function() {
    printTime();
    printAgent();
}

JavaScript ์†Œ์Šค ๋ณด๊ธฐ : ์•„์ด์ฝ˜๊ณผ ๋ฎค์ง ํ”Œ๋ ˆ์ด์–ด๋ฅผ ์ž์œ ์ž์žฌ๋กœ ๋“œ๋ž˜๊ทธ

์•„์ด์ฝ˜๊ณผ ๋ฎค์ง ํ”Œ๋ ˆ์ด์–ด๋ฅผ ์ž์œ ์ž์žฌ๋กœ ๋“œ๋ž˜๊ทธํ•˜์—ฌ ์œ„์น˜ ์ด๋™์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋„๋ก ํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ์ด๋‹ค. jQuery๋ฅผ ์„ค์น˜ํ•˜์—ฌ์•ผ ํ•˜๋ฉฐ ์ž์œ ์ž์žฌ ๋“œ๋ž˜๊ทธ๋ฅผ ์‹œ์ผœ์ฃผ๊ณ ์ž ํ•˜๋Š” div์˜ ํด๋ž˜์Šค๊ฐ’์— .draggable๋ฅผ ๋ถ™์ด๋ฉด ๋œ๋‹ค.

$( function() {
    $(".icon0").draggable();
    $(".icon1").draggable();
    $(".icon2").draggable();
    $(".icon3").draggable();
    $(".icon4").draggable();
    $(".icon5").draggable();
    $(".music__wrap").draggable({
    });
} );

JavaScript ์†Œ์Šค ๋ณด๊ธฐ : ๋ฎค์ง ํ”Œ๋ ˆ์ด์–ด

allMusic ์ƒ์ˆ˜์—๋Š” ์Œ์•… ์ •๋ณด(๊ณก๋ช…, ์•„ํ‹ฐ์ŠคํŠธ, ์ด๋ฏธ์ง€, ์˜ค๋””์˜ค ํŒŒ์ผ๋ช…)๋ฅผ ๋‹ด๊ณ , ํ•„์š”ํ•œ ๋งŒํผ์˜ ์ƒ์ˆ˜๋ฅผ ์„ ์–ธํ•œ๋‹ค. ํ˜„์žฌ ์Œ์•… ์ธ๋ฑ์Šค ๋ฒˆํ˜ธ๋ฅผ ์ฒ˜์Œ์—๋Š” 1๋กœ ์„ค์ •ํ•œ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ์—” ์Œ์•… ์žฌ์ƒ, ์žฌ์ƒ ๋ฒ„ํŠผ, ์ •์ง€ ๋ฒ„ํŠผ, ์ด์ „ ๊ณก ๋“ฃ๊ธฐ ๋ฒ„ํŠผ, ๋‹ค์Œ ๊ณก ๋“ฃ๊ธฐ ๋ฒ„ํŠผ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ง  ๋‹ค์Œ ๋ฒ„ํŠผ์„ ํด๋ฆญํ–ˆ์„ ๋•Œ ํ•ด๋‹น ์Šคํฌ๋ฆฝํŠธ๋“ค์ด ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋„๋ก addEventListener๋ฅผ ์ด์šฉํ•˜์—ฌ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์งœ๋„๋ก ํ•œ๋‹ค. ๊ทธ ์™ธ์—๋„ ๋ฎค์ง ๋ฆฌ์ŠคํŠธ ๊ตฌํ˜„, ๋ฎค์ง ์ง„ํ–‰๋ฐ”, ์˜ค๋””์˜ค๊ฐ€ ๋๋‚ฌ์„ ๋•Œ, ๋ฒ„ํŠผ ๋ฐ”๊ฟ”์ฃผ๊ธฐ ๋“ฑ์˜ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์žˆ์œผ๋ฉฐ ์•„๋ž˜ ์ฝ”๋“œ์˜ ์ฃผ์„ ์ฒ˜๋ฆฌ๋œ ์„ค๋ช…๋ฌธ์„ ์ฐธ๊ณ ํ•˜๋„๋ก ํ•œ๋‹ค.

๋ฎค์ง ํ”Œ๋ ˆ์ด์–ด JS ์†Œ์Šค ๋ณด๊ธฐ
const allMusic = [
    {
        name: "1. Kazoom",
        artist: "Quincas Moreira",
        img: "music-1",
        audio: "music-1"
    },
    {
        name: "2. Calimba",
        artist: "E's Jammy Jams",
        img: "music-2",
        audio: "music-2"
    },
    {
        name: "3. This Old Man (instrumental)",
        artist: "The Green Orbs",
        img: "music-3",
        audio: "music-3"
    },
    {
        name: "4. This Old Man (vocal)",
        artist: "The Green Orbs",
        img: "music-4",
        audio: "music-4"
    },
    {
        name: "5. The Farmer In The Dell",
        artist: "The Green Orbs",
        img: "music-5",
        audio: "music-5"
    },
    {
        name: "6. The Farmer In The Dell (Instrumental)",
        artist: "The Green Orbs",
        img: "music-6",
        audio: "music-6"
    },
    {
        name: "7. Snack Time",
        artist: "The Green Orbs",
        img: "music-7",
        audio: "music-7"
    },
    {
        name: "8. Sand Castles",
        artist: "The Green Orbs",
        img: "music-8",
        audio: "music-8"
    },
    {
        name: "9. Rock-a-bye Baby",
        artist: "The Green Orbs",
        img: "music-9",
        audio: "music-9"
    },
    {
        name: "10. A Walk Into Space",
        artist: "Topher Mohr and Alex Elena",
        img: "music-10",
        audio: "music-10"
    },
]

const musicWrap = document.querySelector(".music__wrap");
const musicView = musicWrap.querySelector(".music__view .img img");
const musicName = musicWrap.querySelector(".music__view .title h3");
const musicArtist = musicWrap.querySelector(".music__view .title p");
const musicAudio = musicWrap.querySelector("#main-audio");
const musicPlay = musicWrap.querySelector("#control-play");
const musicPrevBtn = musicWrap.querySelector("#control-prev");
const musicNextBtn = musicWrap.querySelector("#control-next");
const musicProgress = musicWrap.querySelector(".progress");
const musicProgressBar = musicWrap.querySelector(".progress .bar");
const musicProgressCurrent = musicWrap.querySelector(".progress .timer .current");
const musicProgressDuration = musicWrap.querySelector(".progress .timer .duration");
const musicRepeat = musicWrap.querySelector("#control-repeat");
const musicListBtn = musicWrap.querySelector("#control-list");
const musicList = musicWrap.querySelector(".music__list");
const musicListUl = musicList.querySelector(".music__list ul");

let musicIndex = 1;     // ํ˜„์žฌ ์Œ์•… ์ธ๋ฑ์Šค

// ์Œ์•… ์žฌ์ƒ
function loadMusic(num){
    musicName.innerText = allMusic[num-1].name;     // ๋ฎค์ง ์ด๋ฆ„ ๋กœ๋“œ
    musicArtist.innerText = allMusic[num-1].artist;     // ๋ฎค์ง ์•„ํ‹ฐ์ŠคํŠธ ๋กœ๋“œ
    musicView.src = `../assets/img/${allMusic[num-1].img}.png`;     // ๋ฎค์ง ์ด๋ฏธ์ง€ ๋กœ๋“œ
    musicView.alt = allMusic[num-1].name;       // ๋ฎค์ง ์ด๋ฏธ์ง€ alt ํƒœ๊ทธ ๋กœ๋“œ
    musicAudio.src = `../assets/audio/${allMusic[num-1].audio}.mp3`;    // ๋ฎค์ง ํŒŒ์ผ ๋กœ๋“œ
}
musicAudio.play();

// ์žฌ์ƒ ๋ฒ„ํŠผ
function playMusic() {
    musicWrap.classList.add("paused");
    musicPlay.setAttribute("title", "์ •์ง€");
    musicPlay.setAttribute("class", "stop");
    musicAudio.play();
}

// ์ •์ง€ ๋ฒ„ํŠผ
function pauseMusic() {
    musicWrap.classList.remove("paused");
    musicPlay.setAttribute("title", "์žฌ์ƒ");
    musicPlay.setAttribute("class", "play");
    musicAudio.pause();
}

// ์ด์ „ ๊ณก ๋“ฃ๊ธฐ ๋ฒ„ํŠผ
function prevMusic() {
    // musicIndex --
    musicIndex == 1 ? musicIndex = allMusic.length : musicIndex--;
    loadMusic(musicIndex);
    playMusic();
    playListMusic();        // ์žฌ์ƒ๋ชฉ๋ก ์—…๋ฐ์ดํŠธ
}

// ๋‹ค์Œ ๊ณก ๋“ฃ๊ธฐ ๋ฒ„ํŠผ
function nextMusic() {
    // musicIndex ++
    musicIndex == allMusic.length ? musicIndex = 1 : musicIndex++;
    loadMusic(musicIndex);
    playMusic();
    playListMusic();        // ์žฌ์ƒ๋ชฉ๋ก ์—…๋ฐ์ดํŠธ
}

// ํ”Œ๋ ˆ์ด ๋ฒ„ํŠผ ํด๋ฆญ
musicPlay.addEventListener("click", () => {
    const isMusicPaused = musicWrap.classList.contains("paused");   // ์Œ์•…์ด ์žฌ์ƒ์ค‘
    isMusicPaused ? pauseMusic() : playMusic();
});

// ์ด์ „๊ณก ๋ฒ„ํŠผ ํด๋ฆญ
musicPrevBtn.addEventListener("click", () => {
    prevMusic();
});

// ๋‹ค์Œ๊ณก ๋ฒ„ํŠผ ํด๋ฆญ
musicNextBtn.addEventListener("click", () => {
    nextMusic();
});

// ๋ฎค์ง ๋ฆฌ์ŠคํŠธ ๋ฒ„ํŠผ
musicListBtn.addEventListener("click", () => {
    musicList.classList.add("show");
});

// ๋ฎค์ง ๋ฆฌ์ŠคํŠธ ๊ตฌํ˜„ํ•˜๊ธฐ
for(let i=0; i<allMusic.length; i++){
    let li = `
        <li data-index="${i+1}">
            <strong>${allMusic[i].name}</strong>
            <em>${allMusic[i].artist}</em>
            <audio class="${allMusic[i].audio}" src="../assets/audio/${allMusic[i].audio}.mp3"></audio>
            <span class="audio-duration" id="${allMusic[i].audio}">์žฌ์ƒ์‹œ๊ฐ„</span>
        </li>
    `;

    // musicListUl.innerHTML += li;     // ๋งจ ๋งˆ์ง€๋ง‰ ๊ณก์˜ ์‹œ๊ฐ„๋งŒ ํ‘œ์‹œ๋˜๋Š” ๋ฌธ์ œๆœ‰
    musicListUl.insertAdjacentHTML("beforeend", li);    // ๋ฌธ์ œ ํ•ด๊ฒฐ : ๋ชจ๋“  ๊ณก์˜ ์‹œ๊ฐ„์„ ํ‘œ์‹œ ๊ฐ€๋Šฅ

    // ๋ฆฌ์ŠคํŠธ์— ์Œ์•… ์‹œ๊ฐ„ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
    let liAudioDuration = musicListUl.querySelector(`#${allMusic[i].audio}`);       // ๋ฆฌ์ŠคํŠธ์—์„œ ์‹œ๊ฐ„์„ ํ‘œ์‹œํ•  ์„ ํƒ์ž๋ฅผ ๊ฐ€์ ธ์˜ด
    let liAudio = musicListUl.querySelector(`.${allMusic[i].audio}`);               // ๋ฆฌ์ŠคํŠธ์—์„œ ์˜ค๋””์˜ค๋ฅผ ๊ฐ€์ ธ์˜ด
    liAudio.addEventListener("loadeddata", () => {
        let audioDuration = liAudio.duration;                                       // ์˜ค๋””์˜ค ์ „์ฒด ๊ธธ์ด
        let totalMin = Math.floor(audioDuration / 60);                              // ์ „์ฒด ๊ธธ์ด๋ฅผ ๋ถ„ ๋‹จ์œ„๋กœ ์ชผ๊ฐฌ
        let totalSec = Math.floor(audioDuration % 60);                              // ์ดˆ ๊ณ„์‚ฐ
        if(totalSec < 10) totalSec = `0${totalSec}`;                                // ์•ž ์ž๋ฆฌ์— 0 ์ถ”๊ฐ€
        liAudioDuration.innerText = `${totalMin}:${totalSec}`;                      // ๋ฌธ์ž์—ด ์ถœ๋ ฅ
        liAudioDuration.setAttribute("data-duration", `${totalMin}:${totalSec}`);   // ์†์„ฑ์— ์˜ค๋””์˜ค ๊ธธ์ด ๊ธฐ๋ก
    });
}

// ๋ฎค์ง ๋ฆฌ์ŠคํŠธ๋ฅผ ํด๋ฆญํ•˜๋ฉด ์žฌ์ƒ
function playListMusic(){
    const musicListAll = musicListUl.querySelectorAll("li");    // ๋ฎค์ง ๋ฆฌ์ŠคํŠธ ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ
    for(let i=0; i<musicListAll.length; i++){
        let audioTag = musicListAll[i].querySelector(".audio-duration");

        if(musicListAll[i].classList.contains("playing")){
            musicListAll[i].classList.remove("playing");        // ํด๋ž˜์Šค ์กด์žฌ์‹œ ์‚ญ์ œ
            let adDuration = audioTag.getAttribute("data-duration");    // ์˜ค๋””์˜ค ๊ธธ์ด๊ฐ’ ๊ฐ€์ ธ์˜ค๊ธฐ
            audioTag.innerText = adDuration;    // ์˜ค๋””์˜ค ๊ธธ์ด๊ฐ’ ์ถœ๋ ฅ
        }

        if(musicListAll[i].getAttribute("data-index") == musicIndex){   // ํ˜„์žฌ ๋ฎค์ง์ธ๋ฑ์Šค๋ž‘ ๋ฆฌ์ŠคํŠธ ์ธ๋ฑ์Šค ๊ฐ’์ด ๊ฐ™๋‹ค๋ฉด
            musicListAll[i].classList.add("playing");                   // ํด๋ž˜์Šค playing ์ถ”๊ฐ€
            audioTag.innerText = "์žฌ์ƒ์ค‘";                              // ์žฌ์ƒ์ค‘์ผ ๊ฒฝ์šฐ ์žฌ์ƒ์ค‘ ๋ฉ˜ํŠธ ์ถ”๊ฐ€   
        }

        musicListAll[i].setAttribute("onclick", "clicked(this)");
    }
}

// ๋ฎค์ง ๋ฆฌ์ŠคํŠธ๋ฅผ ํด๋ฆญํ•˜๋ฉด
function clicked(el){
    let getLiIndex = el.getAttribute("data-index");     // ํด๋ฆญํ•œ ๋ฆฌ์ŠคํŠธ์˜ ์ธ๋ฑ์Šค ๊ฐ’์„ ์ €์žฅ
    musicIndex = getLiIndex;    // ํด๋ฆญํ•œ ์ธ๋ฑ์Šค ๊ฐ’์„ ๋ฎค์ง ์ธ๋ฑ์Šค์— ์ €์žฅ
    loadMusic(musicIndex);      // ํ•ด๋‹น ์ธ๋ฑ์Šค ๋ฎค์ง ๋กœ๋“œ
    playMusic();                // ์Œ์•… ์žฌ์ƒ
    playListMusic();            // ์Œ์•… ๋ฆฌ์ŠคํŠธ ์—…๋ฐ์ดํŠธ
}

// ๋ฎค์ง ์ง„ํ–‰๋ฐ”
musicAudio.addEventListener("timeupdate", e => {
    // console.log(e);

    const currentTime = e.target.currentTime;   // ํ˜„์žฌ ์žฌ์ƒ๋˜๋Š” ์‹œ๊ฐ„
    const duration = e.target.duration;         // ์˜ค๋””์˜ค์˜ ์ด ๊ธธ์ด
    let progressWidth = (currentTime/duration) * 100;   // ์ „์ฒด๊ธธ์ด์—์„œ ํ˜„์žฌ ์ง„ํ–‰๋˜๋Š” ์‹œ๊ฐ„์„ ๋ฐฑ๋ถ„์œ„๋กœ ๋‚˜๋ˆ”
    
    musicProgressBar.style.width = `${progressWidth}%`;

    // ์ „์ฒด ์‹œ๊ฐ„
    musicAudio.addEventListener("loadeddata", () => {
        let audioDuration = musicAudio.duration;
        let totalMin = Math.floor(audioDuration / 60);    // ์ „์ฒด์‹œ๊ฐ„์„ ๋ถ„๋‹จ์œ„๋กœ ์ชผ๊ฐฌ
        let totalSec = Math.floor(audioDuration % 60);    // ๋‚จ์€ ์ดˆ๋ฅผ ์ €์žฅ
        if(totalSec < 10) totalSec = `0${totalSec}`;      // ์ดˆ๊ฐ€ ํ•œ์ž๋ฆฌ์ˆ˜์ผ๋•Œ ์ผ์˜ ์ž๋ฆฌ์ˆ˜ ์•ž์— 0์„ ๋ถ™์ž„
        musicProgressDuration.innerText = `${totalMin}:${totalSec}`;    // ์™„์„ฑ๋œ ์‹œ๊ฐ„ ๋ฌธ์ž์—ด                                 
    });

    // ์ง„ํ–‰ ์‹œ๊ฐ„
    let currentMin = Math.floor(currentTime / 60);
    let currentSec = Math.floor(currentTime % 60);
    if(currentSec < 10) currentSec = `0${currentSec}`;
    musicProgressCurrent.innerText = `${currentMin}:${currentSec}`;
});

// ์ง„ํ–‰ ๋ฒ„ํŠผ ํด๋ฆญ
musicProgress.addEventListener("click", (e) => {
    let progressWidth = musicProgress.clientWidth;  // ์ง„ํ–‰๋ฐ” ์ „์ฒด ๊ธธ์ด
    let clickedOffsetX = e.offsetX;                 // ์ง„ํ–‰๋ฐ” ๊ธฐ์ค€์œผ๋กœ ์ธก์ •๋˜๋Š” X์ขŒํ‘œ๊ฐ’
    let songDuration = musicAudio.duration;         // ์˜ค๋””์˜ค ์ „์ฒด ๊ธธ์ด

    musicAudio.currentTime = (clickedOffsetX / progressWidth) * songDuration;   // ๋ฐฑ๋ถ„์œ„๋กœ ๋‚˜๋ˆˆ ์ˆซ์ž์— ๋‹ค์‹œ ์ „์ฒด ๊ธธ์ด๋ฅผ ๊ณฑํ•ด์„œ ํ˜„์žฌ ์žฌ์ƒ๊ฐ’์œผ๋กœ ๋ฐ”๊ฟˆ
});

// ๋ฐ˜๋ณต ๋ฒ„ํŠผ ํด๋ฆญ
musicRepeat.addEventListener("click", () => {
    let getAttr = musicRepeat.getAttribute("class");

    switch(getAttr){
        case "repeat" : 
            musicRepeat.setAttribute("class", "repeat_one");
            musicRepeat.setAttribute("title", "ํ•œ๊ณก ๋ฐ˜๋ณต");
        break;
        case "repeat_one" :
            musicRepeat.setAttribute("class", "shuffle");
            musicRepeat.setAttribute("title", "๋žœ๋ค ์žฌ์ƒ");
        break;
        case "shuffle" : 
            musicRepeat.setAttribute("class", "repeat");
            musicRepeat.setAttribute("title", "์ „์ฒด ๋ฐ˜๋ณต");
        break;
    }
});

// ์˜ค๋””์˜ค๊ฐ€ ๋๋‚˜๋ฉด
musicAudio.addEventListener("ended", () => {
    let getAttr = musicRepeat.getAttribute("class");
    
    switch(getAttr) {
        case "repeat" :
            nextMusic();
        break;
        case "repeat_one" : 
            playMusic();
        break;
        case "shuffle" :
            let randomIndex = Math.floor(Math.random() * allMusic.length + 1);      // ๋žœ๋ค ์ธ๋ฑ์Šค ์ƒ์„ฑ

            do {
                randomIndex = Math.floor(Math.random() * allMusic.length + 1);
            } while ( musicIndex == randomIndex )
                musicIndex = randomIndex;   // ํ˜„์žฌ ์ธ๋ฑ์Šค๋ฅผ ๋žœ๋ค ์ธ๋ฑ์Šค๋กœ ๋ณ€๊ฒฝ
                loadMusic(musicIndex);      // ๋žœ๋ค ์ธ๋ฑ์Šค๊ฐ€ ๋ฐ˜์˜๋œ ํ˜„์žฌ ์ธ๋ฑ์Šค ๊ฐ’์œผ๋กœ ์Œ์•…์„ ๋‹ค์‹œ ๋กœ๋“œ
                playMusic();                // ๋กœ๋“œํ•œ ์Œ์•…์„ ์žฌ์ƒ
            break;
    }
    playListMusic();        // ์žฌ์ƒ๋ชฉ๋ก ์—…๋ฐ์ดํŠธ
});

// ๋ฒ„ํŠผ ๋ฐ”๊ฟ”์ฃผ๊ธฐ
const btnPlay = document.querySelector("#control-play");
const btnStop = document.querySelector("#control-stop");

btnStop.style.display = "none";

btnPlay.addEventListener("click", () => {
    playMusic();
    btnStop.style.display = "block";
    btnPlay.style.display = "none";
});

btnStop.addEventListener("click", () => {
    pauseMusic();
    btnStop.style.display = "none";
    btnPlay.style.display = "block";
});

// ๋กœ๋“œ
window.addEventListener("load", () => {
    loadMusic(musicIndex);  // ์Œ์•… ์žฌ์ƒ
    playListMusic();        // ๋ฆฌ์ŠคํŠธ ์ดˆ๊ธฐํ™”
});

// ๋ฎค์ง ํ”Œ๋ ˆ์ด์–ด ๋ฆฌ์ŠคํŠธ ๋‹ซ๊ธฐ ๋ฒ„ํŠผ ๋ˆ„๋ฅด๋ฉด
const musicListList = document.querySelector(".music__list");
const musicListCloseBtn = document.querySelector("#control-close");

musicListCloseBtn.addEventListener("click", () => {
    musicListList.classList.add("close");
});

// ๋ฎค์ง ํ”Œ๋ ˆ์ด์–ด ๋ฆฌ์ŠคํŠธ ๋ฒ„ํŠผ ๋ˆ„๋ฅด๋ฉด
const musicControlListBtn = document.querySelector(".music__control .list");

musicControlListBtn.addEventListener("click", () => {
    musicListList.classList.remove("close");
});

// ๋ณผ๋ฅจ ์กฐ์ ˆ
const audio = document.getElementById("main-audio");
const audioVolume = document.getElementById("volume-control");
const volumeIcon = document.querySelector(".volume_icon");
const volumeOffIcon = document.querySelector(".volumeOff_icon");

audioVolume.addEventListener("change", function (e) {
    audio.volume = this.value / 10;
    if (this.value == 0) {
        volumeIcon.classList.add("hide");
        volumeOffIcon.classList.add("show");
    } else {
        volumeIcon.classList.remove("hide");
        volumeOffIcon.classList.remove("show");
    }
});

๊ฒฐ๊ณผ

๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€


Reference Book

JavaScript
HTML
CSS
๊ด‘๊ณ  ์ค€๋น„์ค‘์ž…๋‹ˆ๋‹ค.