티스토리 뷰

 

파일구조

HTML

<div class="typing__wrap">
        <input type="text" class="input__field">
        <div class="typing__inner">
            <div class="typing__text">
                <p></p>
            </div>
            <div class="typing__info">
                <ul>
                    <li class="time">
                        <p>Time Left:</p>
                        <span><b>60</b>s</span>
                    </li>
                    <li class="mistake">
                        <p>Mistakes: </p>
                        <span>0</span>
                    </li>
                    <li class="wpm">
                        <p>wpm: </p>
                        <span>0</span>
                    </li>
                    <li class="cpm">
                        <p>cpm: </p>
                        <span>0</span>
                    </li>
                </ul>
                <button class="again">Try Again</button>
            </div>
        </div>
    </div>

CSS

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: "Poppins";
}
body {
    background: #17A2B8;
}
.typing__wrap {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100vh;
}
.typing__inner {
    width: 60vw;
    min-width: 900px;
    min-height: 40vh;
    background: #fff;
    border-radius: 20px;
    padding: 40px;
}
.input__field {
    position: absolute;
    left: 10px;
    top: 10px;
    padding: 10px;
}
.typing__text {
    border: 1px solid #C3C3C3;
    border-radius: 10px;
    padding: 30px;
    min-height: 300px;
    font-size: 22px;
    font-weight: 500;
    text-align: justify;
    word-break: break-all;
}
.typing__text p span {
    position: relative;
}
.typing__text p span.correct {
    color: rgb(54, 20, 245);
}
.typing__text p span.incorrect {
    color: #cd3439;
    background: #ffc0cb;
    outline: 1px solid #ffff;
    border-radius: 4px;
}
.typing__text p span.active {
    color: #17A2B8;
}
.typing__text span.active::before {
    content: '';
    position: absolute;
    left: 0;bottom: 0;
    width: 100%;
    height: 2px;
    background: #17A2B8;
    animation: blink 1s ease-in-out infinite;
    opacity: 0;
}
@keyframes blink {
    50% {opacity: 1;}
}
.typing__info {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-top: 30px;
}
.typing__info button {
    width: 210px;
    background: #17A2B8;
    color:#fff;
    font-family: "Poppins";
    border: 0;
    border-radius: 5px;
    padding: 10px;
    font-size: 22px;
    margin-left: 20px;
    cursor: pointer;
}
.typing__info ul {
    display: flex;
    width: 100%;
    justify-content: space-around;
}
.typing__info ul li {
    /* width: 20%; */
    list-style: none;
    display: flex;
    font-size: 20px;
    border-left: 1px solid #C3C3C3;
    padding-left: 40px;
}
.typing__info ul li:first-child {
    padding-left: 0;
    border-left: 0;
}
.typing__info li p {
    white-space: nowrap;
}       
.typing__info li span {
    padding: 0 10px;
}​

SCRIPT

    <script src="api/music.js"></script>
    <script>
        const musicWrap = document.querySelector(".wrap__music");
        const musicImg = musicWrap.querySelector(".music__img img");
        const musicName = musicWrap.querySelector(".music__song .name");
        const musicArtist = musicWrap.querySelector(".music__song .artist");
        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(".music__progress");
        const musicProgressBar = musicProgress.querySelector(".bar");
        const musicProgressCurrent = musicProgress.querySelector(".current");
        const musicProgressDuration = musicProgress.querySelector(".duration");
        const musicRepect = musicWrap.querySelector("#control-repeat");
        const musicList = musicWrap.querySelector(".music__list");
        const musicListBtn = musicWrap.querySelector("#control-list");
        const musicListClose = musicList.querySelector(".close");
        const musicListUl = musicList.querySelector(".list ul");
    

        let musicIndex = Math.floor((Math.random()*allMusic.length)+1); //현재 재생 음악 인덱스

        //음악 재생
        function loadMusic(num){
            musicImg.src = `images/${allMusic[num-1].img}.jpg`;
            musicImg.alt = allMusic[num-1].name;
            musicName.innerText = allMusic[num-1].name;
            musicArtist.innerText = allMusic[num-1].artist;
            musicAudio.src = `songs/${allMusic[num-1].audio}.mp3`;
        }
        // 음악 플레이 
        function playMusic(){
            musicWrap.classList.add("paused");
            musicPlay.innerText = "pause";
            musicPlay.setAttribute("title", "플레이") //속성 부여 메서드
            musicAudio.play();
        }
        // 음악 정지
        function pauseMusic(){
            musicWrap.classList.remove("paused");
            musicPlay.innerText = "play_arrow";
            musicPlay.setAttribute("title", "정지") //속성 부여 메서드
            musicAudio.pause();
        }
        // 이전 곡 재생
        function pervMusic(){
            musicIndex--;
            musicIndex < 1 ? musicIndex = allMusic.length : musicIndex = musicIndex;
            loadMusic(musicIndex);
            playMusic();
            playListMusic();
        }
        // 다음 곡 재생
        function nextMusic(){
            musicIndex++;
            musicIndex > allMusic.length ? musicIndex = 1 : musicIndex = musicIndex;
            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}`;
                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}`;
        });
        // 플레이 버튼
        musicPlay.addEventListener("click", () => {
            const isMusicPaused = musicWrap.classList.contains("paused");
            isMusicPaused ? pauseMusic() : playMusic();
            playListMusic();
        });
        // 이전 곡 버튼
        musicPrevBtn.addEventListener("click", () => {
            pervMusic();
        });
        // 다음 곡 버튼
        musicNextBtn.addEventListener("click", () => {
            nextMusic();
        });
        // 진행 버튼 클릭
        musicProgress.addEventListener("click", (e) => {
            let progressWidth = musicProgress.clientWidth;
            let clickedOffsetX = e.offsetX;
            let songDuration = musicAudio.duration;

            musicAudio.currentTime = (clickedOffsetX / progressWidth ) * songDuration; //musicAudio의 현재값의 클릭한 지점의 전체 길이값 ) *(곱하기) 노래Duration 
            playMusic();
        })
        //반복 버튼 : 3가지 토글 메뉴 만들기 위해 switch문으로 작성
        musicRepect.addEventListener("click", () => {
            let getText = musicRepect.innerText;
            switch(getText){
                case "repeat" : 
                    musicRepect.innerText = "repeat_one";
                    musicRepect.setAttribute("title", "한곡 반복") //속성 부여 메서드
                break;
                case "repeat_one" : 
                    musicRepect.innerText = "shuffle";
                    musicRepect.setAttribute("title", "랜덤 반복") //속성 부여 메서드
                break;
                case "shuffle" : 
                    musicRepect.innerText = "repeat";
                    musicRepect.setAttribute("title", "전체 반복") //속성 부여 메서드
                break;
            }
        });
        //오디오가 끝나고 
        musicAudio.addEventListener("ended", () => { //ended 00하는 이벤트
            let getText = musicRepect.innerText;

            switch(getText){
                case "repeat" : 
                    nextMusic(); //'다음 곡 재생' 함수 실행
                break;
                case "repeat_one" : 
                    loadMusic(musicIndex); //'현재 재생 음악 인덱스'를 다시 불러옴
                    playMusic(); //'음악 플레이' 함수 실행
                    playListMusic();
                break;
                case "shuffle" : 
                    let randIndex = Math.floor((Math.random()*allMusic.length)+1);
                    do { //조건에 맞는 경우에만 실행
                        randIndex = Math.floor((Math.random()*allMusic.length)+1);
                    } while (musicIndex =+ randIndex); // 맞든 안 맞든 1번은 실행해줌
                    musicIndex = randIndex;
                    loadMusic(randIndex); 
                    playMusic();
                    playListMusic();
                break;
            }
        });
        
        //뮤직 리스트 버튼
        musicListBtn.addEventListener("click", () => {
            musicList.classList.add("show");
        });
       
        // 뮤직 리스트 닫기 버튼
        musicListClose.addEventListener("click", () => {
            musicList.classList.remove("show");
        });

        //뮤직 리스트 구현하기 : musicList Ul에 리스트 삽입
        for(let i = 0; i<allMusic.length; i++){
            let li = `
                        <li data-index="${i+1}">
                            <div>
                                <em>${allMusic[i].name}</em>
                                <p>${allMusic[i].artist}</p>
                            </div>
                            <audio class="${allMusic[i].audio}" src="songs/${allMusic[i].audio}.mp3"></audio>
                            <span id="${allMusic[i].audio}" class="audio-duration">3:36</span>
                        </li> 
            `;
            musicListUl.insertAdjacentHTML("beforeend", li); //musicListUl에 삽입

            //지속시간 표기
            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}`;
                liAudioDuration.innerText = `${totalMin}:${totalSec}`;
                liAudioDuration.setAttribute("data-duration", `${totalMin}:${totalSec}`);
            });
            playListMusic();
        }

        //뮤직 리스트 클릭
        function playListMusic() {
            
            const musicListAll = musicListUl.querySelectorAll("li");

            //현재 재생 음악에 불 들어오게하기
            for(let j=0; j<musicListAll.length; j++){
                let audioTag = musicListAll[j].querySelector(".audio-duration");
                if(musicListAll[j].classList.contains("playing")){
                    musicListAll[j].classList.remove("playing");
                    let adDuration = audioTag.getAttribute("data-duration");
                    audioTag.innerText = adDuration;
                }
                if(musicListAll[j].getAttribute("data-index") == musicIndex){
                    musicListAll[j].classList.add("playing");
                    audioTag.innerText = "재생중";
                }

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

        }

         // 리스트 클릭하기
         function clicked(el){
            let getLiIndex = el.getAttribute("data-index");
            musicIndex = getLiIndex;
            loadMusic(musicIndex);
            playMusic();
            playListMusic();
        }

        // 플레이
        window.addEventListener("load", () => {
            loadMusic(musicIndex);
            playListMusic();
        });
    </script>​

music.js

let allMusic = [
    {
        name : "1.노래제목",
        artist : "아티스트",
        img : "music-1(이미지 파일명)",
        audio : "music-1(음악 파일명)"
    }
}
댓글
© 2018 webstoryboy