April 14, 2020
๋ฎค์ง ํ๋ ์ด์ด ์ฑ์ ๊ฐ๋จํ ๋ง๋ค์ด๋ณด์๋ค. audio DOM element๋ฅผ ์ฒ์ ๋ค๋ค๋ณด์๊ณ , class๋ฅผ ํ์ฉํด OOP๋ ์ ๊ฒฝ์จ์ ๊ตฌํํด๋ณด์๋ค.
ํ๋ฉด ์ค์์๋ Play/Stop ๋ฒํผ๊ณผ ์์์ผ๋ก๋ ์ด์ ๊ณก ๋ฒํผ, ๋ค์๊ณก ๋ฒํผ์ ๋์๋ค.
๊ทธ๋ฆฌ๊ณ ์์ ์ด ์ฌ์์ค์ผ ๋๋ ๋ฐฐ๊ฒฝ ๊ทธ๋ผ๋์ธํธ ์ ๋๋ฉ์ด์ ์ด ๋ณด์ด๋๋ก ํด์ฃผ์๋ค.
<BackgroundContainer className="musicBackground" playToggle={playToggle}>
<ContentsMenubar name="music" />
<audio preload="auto" controls="none" style={{ display: 'none' }}></audio>
<SideButton position="left" onClick={() => anotherMusicPlay('left')} />
<PlayButton onClick={playMusic}>
<div>{myMusic.name}</div>
<p>{!playToggle ? `PLAY` : `STOP`}</p>
</PlayButton>
<SideButton position="right" onClick={() => anotherMusicPlay('right')} />
</BackgroundContainer>
Component | Description |
---|---|
BackgroundContainer | ํด๋น ์ดํ๋ฆฌ์ผ์ด์
์ Full Container styled-component |
ContentsMenubar | ๋ฉ๋ด๋ฐ import |
audio | ์์
๊ด๋ จ html element HTMLAudioElement |
SideButton, PlayButton | ๋ฒํผ element styled-component |
๋จผ์ ์์ ์ ์ปจํธ๋กค ํด์ค class๋ฅผ ๋ฐ๋ก ๋ง๋ค์ด์ฃผ์๋ค.
export default class Sound {
sound = null // HTMLAuioElement
name = ''
constructor(src) {
this.sound = document.querySelector('audio')
this.name = src
this.sound.src = src
}
play() {
this.sound.play()
}
stop() {
this.sound.pause()
}
}
state๋ก๋ HTMLAudioElement์ ์ ๊ทผํ๋ sound์ ์์ ์ด๋ฆ name์ ๋์๊ณ , ๋ชจ๋ ์์ ์ปจํธ๋กค์ Sound๊ฐ์ฒด์์ ํ ์ ์๊ฒ๋ ํด์ฃผ์๋ค.
const musics = ['1Upbeat Ukulele.mp3', '2Instrumental.mp3', '3Inspiration.mp3']
๋จผ์ musics ๋ฐฐ์ด์ ์์ ์ด๋ฆ์ ๋ฃ์ด์ฃผ์๋ค.
useEffect(() => {
setMyMusic(new Sound(musics[0]))
}, [])
๊ทธ๋ฆฌ๊ณ ์ฒ์ ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ๋ ๋, Sound ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ์์ฑ์ ์ธ์๋ก ์ฒซ๋ฒ์งธ ์์ (โ1Upbeat Ukulele.mp3โ)์ ๋ฃ์ด์ฃผ์๋ค. ๊ทธ๋ฆฌ๊ณ ํด๋น ๊ฐ์ฒด๋ฅผ React Hooks์ useState๋ฅผ ์ด์ฉํด์ MyMusic state์ ๋ฃ์ด์ฃผ์๋ค.
const playMusic = () => {
!playToggle && myMusic.play()
playToggle && myMusic.stop()
setPlayToggle(!playToggle)
}
playMusic ํจ์๋ ๊ฐ์ด๋ฐ Play/Stop ๋ฒํผ์ ๋๋ฅด๋ฉด ์คํ๋๋ ํจ์๋ก, ํ์ฌ playToggle ๊ฐ์ ๋ฐ๋ผ, myMusic ์ ๋ฉ์๋์ ์ ๊ทผํ๊ฒ ํด์ฃผ์๋ค.
const anotherMusicPlay = direction => {
myMusic.stop()
if (direction === 'left') {
return setMyMusic(
new Sound(
musics[
(musics.indexOf(myMusic.name) + musics.length - 1) % musics.length
]
)
)
}
if (direction === 'right') {
return setMyMusic(
new Sound(musics[(musics.indexOf(myMusic.name) + 1) % musics.length])
)
}
}
anotherMusicPlay ํจ์๋ ์ฌ์ด๋๋ฒํผ์ ๋๋ ์ ๋ ์คํ๋๋ฉฐ, direction์ด๋ผ๋ ์ธ์(์ด์ ๊ณก์ธ์ง,๋ค์๊ณก์ธ์ง ์ฒดํฌ)๋ฅผ ๋ฐ๋๋ค. ์ฐ์ ํ์ฌ myMusic ๊ฐ์ฒด์ ์์ ์ ๋ฉ์ถ๊ณ ์ธ์์ ๋ฐ๋ฅธ ์กฐ๊ฑด๋ฌธ์ ๋์๋ค. ์กฐ๊ฑด๋ฌธ์ else๋ฌธ์ ์ฌ์ฉํ์ง ์๊ณ if์ return ๊ฐ์ผ๋ก ์ฒ๋ฆฌํด์ฃผ์๋ค.
useEffect(() => {
playToggle && myMusic.play()
}, [myMusic])
๋ค์๊ณก ํน์ ์ด์ ๊ณก์ผ๋ก ๊ฐ์ฒด๊ฐ ๋ฐ๋๋ฉด useEffect๋ฅผ ์ด์ฉํด์ ์์ ์ ํ๋ ์ดํ ์ง ๊ณ์ ์ ์งํ ๊ฒ์ธ์ง ์ ํ ์ ์๋๋ก ํ์๋ค.
๋ฐฑ๊ทธ๋ผ์ด๋ ์ ๋๋ฉ์ด์ ์ styled-component ๋ฅผ ์ด์ฉํ๊ณ , codepen.io์ ์์ค๋ฅผ ์ฐธ๊ณ ํ์๋ค.
const rainbow = keyframes`
0%{background-position:0% 82%}
50%{background-position:100% 19%}
100%{background-position:0% 82%}
`
const BackgroundContainer = styled.div`
position: relative;
display: flex;
justify-content: center;
align-items: center;
width: 100vw;
height: 100vh;
background: ${(props) => {
return props.playToggle
? 'linear-gradient(124deg,#ff2400,#e81d1d,#e8b71d,#e3e81d,#1de840,#1ddde8,#2b1de8,#dd00f3,#dd00f3);'
: 'white'
}}
background-size: 1800% 1800%;
animation: ${rainbow} 18s ease infinite;
๋ง๋ค๊ณ ๋๋ ๋๋ฌด ๊ฐ๋จํ๋ ๊ฒ ๊ฐ๋ค. ๊ทธ๋์ ๋ค์์๋ ์น์์ ํ ์ ์๋ ๋๋ผ์ด๋ ์ ๋์ฌ์ด์ ์ดํ์ด๋ ์ ๋ง ๋ฎค์ง ํ๋ ์ด์ด ์ฒ๋ผ ์ฌ๋ฌ ๊ธฐ๋ฅ๋ค์ ๋ฃ์ด๋ณด๊ณ ์ถ๋ค.
์ ๋๋ฉ์ด์ ๊ธฐ๋ฅ๋ ๋ฒํผ์ ๋ฐ์ํ๋๋ก ํ๊ณ ์ถ์๋๋ฐ ์ข์ฒ๋ผ ์ฝ๊ฒ ๋์ง ์์๋ค. ์ค๋ณต ์ ๋๋ฉ์ด์ ์ด ์๋๋ ๊ฒ ๊ฐ๊ธฐ๋ํ๊ณ โฆ ๋ค์ ์๋ง๋ฒ ํ๋ก์ ํธ๋ ์ ๋๋ฉ์ด์ ์ ๋ํด์ ๋ค๋ค๋ณผ๊น ํ๋ค.