들어가기
개발자지만 아이러니하게도 이세계 MBTI를 만들면서 개발만큼 신경썼던 부분이 디자인이었다.
몇 번 개발을 하면서 '내가 힘들게 만든 내 새끼... 다른 사람들도 봐주면 좋을텐데' 라는 생각이 많이 들었다.
MBTI 테스트를 2번이나 만든 이유도 MBTI 테스트 같은 스낵 컨텐츠는 비교적 유저 유입이 쉬울 것 같아서였다.
실제로 지인이 필요한 곰곰 다이어리(ㅠㅠ)는 참여율이 저조했으나 이세계 MBTI는 단시간 내 제법 높은 유입을 기록했다.
요는 사람들이 할만한 테스트를 만들고 싶었던 건데, box-shadow, text-shadow 등 몽환적인 톤앤매너를 가져가는 동시에 게임 사이트처럼 BGM을 넣고 싶었다. 우연히 어떤 게임 사이트를 들어갔는데 BGM이 잘 어울려서 이것저것 눌러봤던 개인적인 경험이 있었기 때문이다.
우리 이세계 MBTI 테스트도 진짜 이세계에 떨어진 것처럼 몰입하게 노래를 틀어보자!
원래는 레전드인 테일즈위버의 레미니센스를 넣고 싶었는데 저작권에 위배되는 듯 해 제외했다.
(유튜브에서 링크를 따오려 했으나 그런 식으로 동영상의 화면 없이 음악만 재생되는 경우도 저작권에 위배되는듯?)
혹시 몰라 무료 음원을 서치했고 마음에 드는 느낌의 mp3 파일을 다운 받았다.
Audio 태그
<audio>는 웹 페이지에서 오디오를 재생하는데 사용되는 요소로 MP3, WAV, OGG 등 다양한 오디오 포맷 파일을 웹에서 재생할 수 있다.
- src 속성: 오디오 파일의 경로를 지정한다.
- autoplay 속성: 자동 재생 여부를 설정한다.
- loop 속성: 반복 재생 여부를 설정한다.
- controls 속성: 컨트롤 패널 노출 여부를 설정한다.
- muted 속성: 음소거 기능을 설정한다.
대부분의 브라우저에서는 유저의 어떤 액션이 없는 한 자동 음원 재생을 지원하지 않는다.
오디오 객체를 로드하고 자동으로 play() 메서드를 설정해 음원을 재생하게 하면 브라우저 상에서 이를 차단해버린다.
const music = new Audio('music.mp3');
music.play();
이전에는 크롬 브라우저에서 JS를 이용해 음원을 자동으로 재생하는 게 가능했지만 보안의 위협이 될 수도 있다고 한다.
MDN에 의하면 아래의 조건 중 하나라도 해당되면 자동 재생이 가능하다.
- 음소거이거나 오디오의 볼륨이 0일 경우
- 유저가 사이트와 상호작용하는 경우 (클릭, 터치, 키 입력 등)
- 화이트리스트에 등록된 사이트
- 자동 재생 정책이 허용으로 지정돼 <iframe>와 document에서 자동 재생을 지원하는 경우
이 외의 경우에는 자동 재생이 차단된다. 더불어 자동 재생은 유저에게 불쾌한 경험(unpleasant)이 될 수도 있으므로 지양하는 것이 좋다.
이세계 MBIT에서는
<MusicPlayer onClick={handleMusicStart}>
<Music src={getMusicIcon()} alt="음악 플레이어 아이콘" />
</MusicPlayer>
MusicPlayer 컴포넌트는 button으로 음악을 재생하고 멈출 수 있다.
Music 컴포넌트는 그 버튼 안에 들어가는 재생(음표) / 정지(뮤트) img다.
원하는 기능의 세부 사항은 다음과 같다.
1. 유저가 한 번 클릭하면 음악이 재생되고 한 번 더 클릭하면 음악이 정지된다. 다시 클릭하면 또 재생된다.
2. 음악의 볼륨이 줄어든 상태로 재생되는 게 아니라 노래를 아예 멈추고 싶다.
3. 다시 재생할 때 처음부터 재생되는 게 아니라 정지시킨 부분부터 재생하고 싶다.
4. 노래가 다 끝나면 다시 재생되게 하고 싶다.
먼저 재생 여부 상태를 관리할 state를 만들어준다.
다음 audio 객체를 생성한 뒤, 노래가 끝나도 다시 재생되게 loop 속성을 true로 설정한다.
이 때 useMemo로 값을 메모이제이션 하지 않으면 2가지 문제가 생긴다.
1. Audio 객체가 매 렌더링마다 생성되어 불필요한 리소스가 소모된다.
2. 클릭(재생) -> 클릭(정지) -> 클릭(재생) 이 되지 않고 모두 재생이 되어 버린다.
따라서 audio 객체로 만든 audio는 loop 속성이 true이며,
첫 렌더링 시에만 객체가 생성되고 이후에는 메모이제이션된 값이 재사용된다.
const [isPlaying, setIsPlaying] = useState(false);
const music = useMemo(() => {
const audio = new Audio('/music/ost.mp3');
audio.loop = true;
return audio;
}, []);
const handleMusicStart = () => {
if (!isPlaying) {
music.play();
setIsPlaying(true);
} else {
music.pause();
setIsPlaying(false);
}
};
버튼을 클릭할 때마다 handleMusicStart가 실행되는데 만약 재생하고 있다면 일시 정지와 더불어 정지 상태로,
재생하지 않고 있다면 재생과 더불어 재생 상태로 불리언 값을 바꿔준다.
useEffect(() => {
const handleEnded = () => {
setIsPlaying(false);
};
music.addEventListener('ended', handleEnded);
return () => {
music.removeEventListener('ended', handleEnded);
};
}, [music]);
music값이 바뀔 때마다 실행되는 useEffect 훅을 만들었다.
'ended'는 audio 태그에서 음악이 종료될 때 발생하는 이벤트다.
즉 노래가 끝나면 정지 상태로 바꾸고 클린업 함수를 통해 ended 이벤트 리스너를 제거한다.
const getMusicIcon = () => {
return isPlaying ? '/img/icon/music.png' : '/img/icon/mute.png';
};
버튼 안의 이미지는 재생 상태에 따라 바뀐다.
재생하고 있으면 음표 아이콘을, 정지했으면 뮤트 아이콘을 띄워줬다.
브라우저에서 자동 재생이 지원되지 않은 이유, audio 객체에 대해 조금 더 자세히 알게 되었다. 👍🏻
**참고
🔊 웹에서 음악 객체(Audio) 다루기
HTML Audio 태그 HTML 태그는 웹 페이지에서 오디오를 재생하기 위해 사용되는 요소이다. MP3, WAV, OGG 등 다양한 오디오 포맷 파일을 웹에서 재생할 수 있다. audio 태그 속성 속성 값 설정 내용 src 파일
inpa.tistory.com
미디어 및 Web Audio API 자동 재생 가이드 - 웹 미디어 기술 | MDN
페이지가 로드 되자마자 소리(또는 소리가 나는 영상)를 자동으로 재생하는 것은 사용자에게 별로 유쾌한 경험은 아닐겁니다. 미디어 자동 재생이 유용하려면 꼭 필요한 경우에 한하여 조심스
developer.mozilla.org
HTMLAudioElement: Audio() constructor - Web APIs | MDN
The Audio() constructor creates and returns a new HTMLAudioElement which can be either attached to a document for the user to interact with and/or listen to, or can be used offscreen to manage and play audio.
developer.mozilla.org
'🛠️ 프로젝트 > ⭐️ 이세계 테스트' 카테고리의 다른 글
[이세계 MBTI 테스트] styled-components의 장단점, 동작 원리 이해하기 (0) | 2024.03.09 |
---|---|
[이세계 MBTI 테스트] React SPA로 만드는 MBTI 테스트 (7) | 2024.02.28 |
[이세계 MBTI 테스트] lighthouse로 웹사이트 성능 측정 및 개선하기 (0) | 2024.02.17 |
[이세계 MBTI 테스트] 웹페이지에 광고 붙이기 : 카카오 애드핏 + 커스텀 훅 + React script 태그 (0) | 2024.02.16 |
[이세계 MBTI 테스트] 리액트 로딩 스피너 라이브러리 react-spinner (0) | 2024.02.04 |