데이터를 언제까지 보관할 것인지에 따라 두 가지 저장소를 골라 쓸 수 있습니다.
브라우저를 껐다 켜도, 컴퓨터를 재부팅해도 데이터가 영구적으로 보존됩니다. (다크모드 설정, 자동 로그인 토큰 등)
현재 열려있는 브라우저 탭(세션) 안에서만 유지되며, 탭을 닫으면 즉시 소멸합니다. (일회성 폼 입력값, 보안 세션 등)
| 메서드 (Method) | 설명 및 역할 |
|---|---|
setItem('key', 'value') |
데이터를 저장합니다. 값(value)은 반드시 문자열(String) 형태로만 저장됩니다. 객체를 저장하려면 JSON.stringify()가 필요합니다. |
getItem('key') |
키를 이용해 저장된 데이터를 불러옵니다. 데이터가 없으면 null을 반환합니다. |
removeItem('key') |
특정 키에 해당하는 데이터만 삭제합니다. |
clear() |
해당 도메인의 스토리지에 저장된 모든 데이터를 일괄 삭제합니다. |
<div class="storage-demo">
<h3>Web Storage 테스트</h3>
<div class="controls">
<button id="btnSaveLocal" class="btn primary">로컬 스토리지에 저장 (영구)</button>
<button id="btnSaveSession" class="btn secondary">세션 스토리지에 저장 (일시)</button>
<button id="btnLoad" class="btn success">저장된 값 불러오기</button>
<button id="btnClear" class="btn danger">스토리지 모두 지우기</button>
</div>
</div>window.addEventListener('scroll')을 사용해야 했는데, 이는 스크롤 할 때마다 수천 번의 함수를 실행시켜 심각한 성능 저하(버벅임)를 유발했습니다. Intersection Observer는 브라우저 내부적으로 최적화되어 작동하므로 성능 저하 없이 부드러운 스크롤 감지가 가능합니다.
"화면에 보여? 안 보여? 지금은? 지금은? 지금은?"
스크롤을 1px 움직일 때마다 위치를 계산하며 끊임없이 질문합니다. 브라우저가 매우 피곤해집니다.
"나는 잘 테니까, 저 영역에 누군가 들어오면 알람 울려줘."
스마트 CCTV를 설치한 것처럼, 조건(예: 50% 보임)이 달성될 때만 조용히 알림(콜백 함수)을 보내줍니다.
| 옵션명 | 설명 |
|---|---|
| root | 관찰의 기준이 되는 부모 컨테이너 요소를 지정합니다. 기본값은 null이며, 이는 브라우저의 뷰포트(전체 화면)를 의미합니다. |
| rootMargin | 관찰 영역을 늘리거나 줄일 수 있는 마진 값입니다. (예: "100px 0px"로 설정하면 화면에 진입하기 100px 전부터 감지합니다. 무한 스크롤(Lazy Load) 선행 로딩에 유용합니다.) |
| threshold | 대상 요소가 얼마나 보여졌을 때 알림을 받을지 0.0 ~ 1.0 사이의 값으로 설정합니다. 0이면 1px라도 보이면 실행, 1.0이면 요소 전체가 완벽히 보여야 실행됩니다. (배열로 여러 값을 설정할 수도 있습니다.) |
<div class="observer-app">
<div class="header">
<h2>아래로 스크롤 해보세요</h2>
<p>요소가 화면에 나타나면 애니메이션이 실행됩니다.</p>
</div>
<div class="scroll-container">
<div class="box">박스 1 (항상 보임)</div>
<div class="box fade-target">박스 2 (Fade In)</div>
<div class="box fade-target">박스 3 (Fade In)</div>
<div class="box fade-target">박스 4 (Fade In)</div>
<div class="box fade-target">박스 5 (Fade In)</div>
</div>
<div class="log-panel" id="logPanel">대기 중...</div>
</div>
[그림 1] Handshake 이후 형성된 실시간 양방향 통신 터널 (WebSocket 구조)
HTTP Polling(주기적 요청)과 WebSocket 통신 방식을 비교한 다이어그램입니다.
서버와의 연결 상태가 변하거나 데이터가 도착할 때 발생하는 이벤트들입니다.
| 이벤트명 | 발생 시점 및 설명 |
|---|---|
open (onopen) |
서버와의 핸드셰이크가 성공하여 데이터 송수신 준비가 완료되었을 때 발생합니다. |
message (onmessage) |
서버로부터 데이터를 수신했을 때 발생합니다. event.data 속성을 통해 메시지를 읽을 수 있습니다. |
error (onerror) |
통신 중 에러가 발생했을 때 호출됩니다. |
close (onclose) |
서버와의 연결이 종료되었을 때 발생합니다. 서버 다운, 네트워크 단절, 명시적 close 호출 시 발동됩니다. |
| 메서드명 | 설명 |
|---|---|
send(data) |
서버로 데이터를 전송합니다. 문자열뿐만 아니라 Blob, ArrayBuffer 등의 바이너리 데이터도 보낼 수 있습니다. |
close([code, reason]) |
웹소켓 연결을 명시적으로 종료합니다. 선택적으로 상태 코드와 종료 사유를 전달할 수 있습니다. |
| 속성명 | 설명 |
|---|---|
readyState |
현재 연결 상태를 나타내는 숫자값입니다. (0: CONNECTING, 1: OPEN, 2: CLOSING, 3: CLOSED) |
bufferedAmount |
send()를 통해 큐에 등록되었지만 네트워크를 통해 아직 전송되지 않은 데이터의 바이트 크기를 반환합니다. |
url |
인스턴스가 연결된 절대 URL을 반환합니다. |
<!-- index.html -->
<div class="chat-container">
<div class="chat-header">
<div style="font-weight: 600;">WebSocket Echo Server</div>
<div>
<span class="status-dot" id="statusDot"></span>
<span class="status-text" id="statusText">연결 중...</span>
</div>
</div>
<div class="chat-messages" id="chatMessages">
<!-- 메시지들이 여기에 추가됩니다 -->
</div>
<form class="chat-input-area" id="chatForm">
<input type="text" id="messageInput" class="chat-input" placeholder="메시지를 입력하세요..." autocomplete="off" disabled>
<button type="submit" id="sendBtn" class="send-btn" disabled>전송</button>
</form>
</div>
[그림 1] 매끄러운 선명도의 SVG(좌측)와 픽셀 깨짐 현상이 발생하는 일반 이미지(우측) 비교
벡터 그래픽인 SVG와 래스터(비트맵) 그래픽인 PNG/JPG의 확대 시 차이점을 보여주는 다이어그램입니다.
HTML 내에 <svg> 요소를 선언한 뒤, 내부에 도형 태그를 사용하여 그림을 그립니다.
| 태그명 | 설명 및 핵심 속성 |
|---|---|
<rect> |
사각형을 그립니다. x, y(시작점), width, height(크기), rx, ry(둥근 모서리) 속성을 사용합니다. |
<circle> |
원을 그립니다. cx, cy(중심점 좌표), r(반지름) 속성을 사용합니다. |
<line> |
선분을 그립니다. x1, y1(시작점)에서 x2, y2(끝점)로 이어집니다. |
<polygon> |
다각형을 그립니다. points="x1,y1 x2,y2..." 형태로 점들을 연결하며, 마지막 점은 처음과 자동으로 연결됩니다. |
<path> |
가장 강력한 태그로 복잡한 곡선이나 아이콘을 그릴 때 사용합니다. d="..." 속성 안에 명령어(M, L, C, Z 등)를 조합합니다. |
SVG는 고유의 속성(Attribute)을 이용해 색상이나 두께를 지정하며, 이는 CSS로도 동일하게 제어할 수 있습니다.
| 속성명 (CSS 호환) | 설명 |
|---|---|
fill |
도형의 내부 채우기 색상을 지정합니다. none으로 설정하면 투명해집니다. |
stroke |
도형의 윤곽선(테두리) 색상을 지정합니다. |
stroke-width |
윤곽선의 두께를 지정합니다. |
viewBox |
(<svg> 전용 속성) 내부 좌표계의 범위를 "min-x min-y width height" 형식으로 정의하여 반응형 크기 조절의 기준이 됩니다. |
<div class="svg-container">
<!-- 반응형 유지와 Hover 시 요소가 잘리지 않도록 viewBox 여백 확대 (-15 -15 130 130) -->
<svg class="interactive-svg" viewBox="-15 -15 130 130" xmlns="http://www.w3.org/2000/svg">
<!-- 배경 원 -->
<circle cx="50" cy="50" r="55" fill="#1e293b" stroke="#3b82f6" stroke-width="2" />
<!-- CSS 클래스로 제어할 다각형 (별 모양) -->
<polygon id="magicStar" class="star"
points="50,15 61,35 85,35 66,50 73,75 50,60 27,75 34,50 15,35 39,35" />
<!-- JavaScript로 조작할 텍스트 -->
<text id="statusText" x="50" y="90" text-anchor="middle" fill="#94a3b8" font-size="8">Hover or Click the Star</text>
</svg>
</div>postMessage로 데이터를 교환해야 합니다.)
[그림 1] 메인 스레드와 워커 스레드의 병렬 처리 아키텍처
메인 스레드와 워커 스레드가 메시지를 주고받으며 연산을 분담하는 과정입니다.
스레드 간 통신을 위해 사용되는 API들입니다.
| 메서드 / 이벤트 | 설명 |
|---|---|
new Worker(scriptURL) |
지정된 자바스크립트 파일을 로드하여 새로운 워커 스레드를 생성합니다. |
postMessage(data) |
메인 스레드와 워커 스레드 간에 데이터를 전송합니다. 전송된 데이터는 복사본(Clone)으로 전달됩니다. |
onmessage (이벤트) |
상대방으로부터 postMessage를 통해 메시지를 받았을 때 발생하는 이벤트입니다. event.data로 값을 읽습니다. |
terminate() |
워커 스레드의 실행을 즉시 종료합니다. (워커 내부에서는 self.close()를 사용) |
<div class="worker-container">
<h3>Web Workers API (Background Sync)</h3>
<p>메인 스레드를 멈추지 않고 복잡한 계산을 백그라운드에서 처리합니다.</p>
<button id="startBtn" class="btn">무거운 계산 시작</button>
<div id="result" class="result-box">결과 대기 중...</div>
</div>IndexedDB는 브라우저 내부에 내장된 강력한 NoSQL 방식의 비동기 데이터베이스입니다. 단순한 키-값 쌍을 넘어, 파일, Blob, 객체 등 구조화된 대용량 데이터를 저장하고 인덱스를 이용해 고속으로 검색할 수 있습니다. Web Storage(5MB)의 용량 한계를 극복하고 오프라인 웹 애플리케이션(PWA)을 구축할 때 핵심적인 역할을 합니다.
| 개념 (Concept) | 설명 및 역할 |
|---|---|
Database |
데이터베이스의 최상위 컨테이너입니다. 버전을 가지며, 버전이 올라갈 때만 구조를 변경할 수 있습니다. |
Object Store |
관계형 DB의 '테이블(Table)'에 해당합니다. 실제 데이터 레코드(JavaScript 객체)가 저장되는 공간입니다. |
Transaction |
DB를 읽거나 쓰는 모든 작업은 트랜잭션 내에서 이루어져야 합니다. (데이터 무결성 보장) |
Cursor |
Object Store 내의 데이터를 순회하며 읽어올 때 사용하는 반복자(Iterator)입니다. |
IndexedDB는 순수 Promise 기반이 아닌 이벤트(DOM Event) 기반 비동기 API입니다. 요청 객체(Request)에 onsuccess, onerror 핸들러를 등록하여 결과를 처리해야 하므로 코드가 길어질 수 있습니다. 실무에서는 이를 Promise로 래핑한 idb 같은 라이브러리를 주로 사용합니다.
<div class="db-demo">
<h3>도서 관리 시스템 (IndexedDB)</h3>
<div class="input-group">
<input type="text" id="bookTitle" placeholder="도서 제목을 입력하세요">
<input type="text" id="bookAuthor" placeholder="저자 입력">
</div>
<div class="controls">
<button id="btnAdd" class="btn primary">책 추가하기</button>
<button id="btnRead" class="btn success">모든 책 불러오기</button>
<button id="btnClear" class="btn danger">DB 초기화 (삭제)</button>
</div>
</div>
[그림 1] 스마트폰의 3D 공간 상의 물리적 회전 및 가속도 측정
디바이스의 방향을 정의하는 세 가지 핵심 축(X, Y, Z)에 대한 구조도입니다.
deviceorientation 이벤트는 기기의 물리적인 방향(각도) 변화를 반환합니다.
| 속성 (event.*) | 설명 |
|---|---|
alpha |
Z축을 기준으로 한 수평 회전 각도 (0 ~ 360). 0은 보통 지구의 북극점을 가리킵니다. |
beta |
X축을 기준으로 한 앞뒤 기울임 각도 (-180 ~ 180). 앞(화면)으로 숙이면 양수입니다. |
gamma |
Y축을 기준으로 한 좌우 기울임 각도 (-90 ~ 90). 우측으로 기울이면 양수입니다. |
absolute |
제공된 방향 데이터가 지구 좌표계(나침반)와 절대적으로 일치하는지(true) 기기 임의 기준선인지(false) 나타냅니다. |
devicemotion 이벤트는 기기가 이동하거나 회전할 때 발생하는 가속도 정보를 반환합니다.
| 속성 (event.*) | 설명 |
|---|---|
acceleration |
중력을 제외한 순수 기기의 가속도 (x, y, z 속성 보유). 단위: m/s² |
accelerationIncludingGravity |
중력 가속도(9.81m/s²)를 포함한 가속도 (x, y, z). 자이로스코프가 없는 기기에서도 지원됩니다. |
rotationRate |
각 축(alpha, beta, gamma)을 중심으로 기기가 회전하는 속도. 단위: 도/초 (deg/s) |
interval |
이벤트가 발생하는 시간 간격 (밀리초). 디바이스의 센서 스펙에 따라 다릅니다. |
최신 iOS 기기(Safari)에서는 개인정보 보호를 위해 사용자의 명시적인 승인 없이 센서 데이터 접근이 차단됩니다. DeviceOrientationEvent.requestPermission() 메서드를 사용해 버튼 클릭과 같은 명시적 사용자 상호작용 내에서 권한을 먼저 요청해야 합니다. 또한 이 API는 기본적으로 HTTPS 환경에서만 동작합니다.
<div class="orient-container">
<h3>Device Orientation API</h3>
<p>모바일 기기의 기울기에 따라 박스가 움직입니다. (에뮬레이터 필요)</p>
<div class="box-area">
<div id="movingBox" class="moving-box">M</div>
</div>
<div id="info" class="info">Alpha: 0 | Beta: 0 | Gamma: 0</div>
</div>z-index 속성을 조작하며 "어떤 요소가 가장 위에 있는지" 싸워야 했습니다.popover 속성 하나로 이 모든 것을 해결할 수 있습니다. 자바스크립트 한 줄 없이도 바깥을 누르면 닫히는(Light Dismiss) 완벽한 팝업이 만들어집니다!
버튼을 누르면 브라우저가 알아서 다른 모든 요소를 무시하고 최상단(Top Layer)에 팝업을 띄워줍니다.
| 속성명 | 적용 태그 | 설명 및 역할 |
|---|---|---|
popover |
팝업 박스 (<div>) |
이 요소가 팝업임을 브라우저에 알립니다. 평소에는 자동으로 display: none 처리되어 숨겨집니다. |
popovertarget="id" |
버튼 (<button>) |
어떤 ID를 가진 팝업을 열 것인지 타겟을 지정합니다. 클릭하면 타겟 팝업이 화면 중앙 최상단에 열립니다. |
popovertargetaction |
버튼 (<button>) |
버튼의 동작을 명시합니다. hide(닫기), show(열기), toggle(열고닫기, 기본값) 중 선택합니다. |
::backdrop |
CSS 선택자 | 팝업이 떴을 때 뒤쪽에 깔리는 어두운 배경 화면을 스타일링하는 가상 요소입니다. 블러(blur) 효과 등을 줄 수 있습니다. |
<div class="demo-container">
<h2>🎉 네이티브 Popover API</h2>
<p class="hint">자바스크립트 한 줄 없이 작동하는 팝업입니다!</p>
<!-- 1. 팝업을 열 트리거 버튼 -->
<!-- popovertarget 속성에 열고자 하는 팝업의 ID를 적습니다. -->
<button popovertarget="info-tooltip" class="action-btn">
마법의 팝업 열기 ✨
</button>
<!-- 2. 실제 팝업 영역 -->
<!-- popover 속성만 추가하면 평소에는 display: none 상태로 숨겨집니다. -->
<!-- Top Layer(최상단)에 그려지므로 z-index 싸움을 할 필요가 없습니다. -->
<div id="info-tooltip" popover class="popover-box">
<h3>안녕? 난 팝업이야! 🎈</h3>
<p>바깥의 어두운 영역(Backdrop)을 클릭하거나<br>ESC 키를 누르면 알아서 닫힙니다.</p>
<hr>
<!-- 팝업 내부의 닫기 버튼 (popovertargetaction="hide") -->
<button popovertarget="info-tooltip" popovertargetaction="hide" class="close-btn">
닫기
</button>
</div>
</div>Fetch API는 기존의 낡은 XMLHttpRequest(XHR)를 대체하기 위해 등장한 강력하고 현대적인 웹 네트워크 통신 API입니다.async/await 문법과 찰떡궁합을 자랑합니다. 최신 웹 브라우저에 내장되어 있어 별도의 라이브러리(axios 등) 설치 없이도 즉시 서버와 데이터를 주고받을 수 있습니다.
서버에 데이터를 요청하고, 성공적으로 받았는지 확인하는 과정입니다.
서버라는 멀리 있는 창고에 택배 기사를 보냅니다. 기사가 왕복하는 데 시간이 걸리므로 비동기(Promise)로 동작하며 다른 작업을 멈추지 않습니다.
택배가 무사히 도착했는지 상태(response.ok)를 확인한 후, 택배 상자를 열어 내용물(JSON 데이터)을 우리가 쓸 수 있는 자바스크립트 객체로 파싱합니다.
| 특징 | 상세 설명 |
|---|---|
| Promise 기반 설계 | 콜백(Callback) 지옥을 유발하던 과거 방식과 달리, .then()이나 async/await를 통해 비동기 코드를 동기 코드처럼 매우 깔끔하게 작성할 수 있습니다. |
| HTTP 에러 처리 주의 | axios와 달리, fetch는 HTTP 404나 500 에러가 발생해도 네트워크 자체가 끊기지 않았다면 에러(catch)로 빠지지 않습니다. 반드시 response.ok로 성공 여부를 따로 검사해야 합니다. |
| 내장 표준 (Native) | React, Vue, 바닐라 JS 어디서든 무거운 외부 라이브러리 설치 없이 즉시 사용할 수 있는 모던 브라우저의 글로벌 표준 규격입니다. |
<div class="fetch-demo">
<h2>사용자 데이터 로더 (Fetch API)</h2>
<p class="desc">버튼을 누르면 외부 서버(JSONPlaceholder)에서 데이터를 가져옵니다.</p>
<button id="fetchBtn" class="action-btn">
<span class="icon">🚀</span> 데이터 가져오기
</button>
<!-- 데이터가 표시될 영역 -->
<div id="resultCard" class="result-card hidden">
<div class="loader" id="loader">로딩 중...</div>
<div id="userData" class="user-data hidden">
<div class="avatar">👤</div>
<div class="info">
<h3 id="userName">이름</h3>
<p id="userEmail" class="email">이메일</p>
<p id="userCompany" class="company">회사</p>
</div>
</div>
<div id="errorMsg" class="error-msg hidden">
데이터를 불러오는데 실패했습니다.
</div>
</div>
</div>새로운 포탈을 엽니다. 주소창은 바뀌지만 우주는 다시 만들어지지(새로고침) 않습니다. 포탈을 넘어갈 때마다 뒤로 갈 수 있는 '발자국(히스토리 스택)'이 하나씩 쌓입니다.
사용자가 브라우저의 뒤로가기 버튼을 눌렀을 때 발동하는 알람입니다. 자바스크립트는 이 알람을 듣고 남겨진 발자국(이전 상태 객체)을 확인하여 과거 화면을 복원합니다.
| API 형태 | 역할 및 설명 |
|---|---|
history.pushState(state, title, url) |
새로운 상태 객체와 함께 주소창의 URL을 변경합니다. 히스토리 스택에 새 기록이 추가되므로 브라우저 뒤로가기 버튼이 활성화됩니다. |
history.replaceState(state, title, url) |
새 기록을 추가하지 않고, 현재 히스토리 기록을 덮어씌우며 URL을 변경합니다. (리다이렉트 처리 등에 유용) |
window.onpopstate = () => {} |
브라우저의 뒤로가기/앞으로가기 버튼을 누르거나 history.back()이 호출될 때 발생하는 이벤트입니다. pushState로 넣었던 state 객체를 꺼내 쓸 수 있습니다. |
<!-- NO_PREVIEW -->
<div class="spa-app">
<nav class="navbar">
<div class="logo">🚀 MinSPA</div>
<ul class="nav-links">
<li><a href="/" class="nav-link" data-path="/">홈</a></li>
<li><a href="/profile" class="nav-link" data-path="/profile">프로필</a></li>
<li><a href="/settings" class="nav-link" data-path="/settings">설정</a></li>
</ul>
</nav>
<main id="app-content" class="content-area">
<!-- 콘텐츠가 동적으로 렌더링되는 영역 -->
</main>
<div class="history-log">
<strong>히스토리 스택 상태:</strong> <span id="historyLength">1</span>개
</div>
</div>
유저가 <input type="file">로 파일을 선택하면 전달받는 상자입니다. 상자 겉면의 송장(이름, 크기, 타입)만 읽을 수 있고, 아직 내용물은 볼 수 없습니다.
택배 상자를 뜯어 내용물을 브라우저가 이해할 수 있는 형태(텍스트, 이미지 URL 등)로 스캔해주는 기계입니다. 변환이 끝나면 onload 알림을 줍니다.
| 메서드 (읽기 방식) | 설명 및 반환 결과 (e.target.result) |
|---|---|
readAsDataURL(file) |
파일을 Base64로 인코딩된 문자열 형태의 Data URL로 읽어옵니다. 주로 <img> 태그의 src 속성에 넣어 이미지 미리보기를 구현할 때 가장 많이 사용됩니다. |
readAsText(file) |
파일을 일반적인 텍스트(문자열)로 읽어옵니다. 텍스트 파일(txt)이나 CSV, JSON 파일을 클라이언트에서 파싱할 때 유용합니다. |
readAsArrayBuffer(file) |
파일을 바이너리 데이터 버퍼인 ArrayBuffer로 읽어옵니다. 오디오/비디오 파일을 자르거나 웹소켓을 통한 스트리밍 전송 등 저수준의 데이터 조작이 필요할 때 사용됩니다. |
<div class="file-app">
<div class="header">
<h2>이미지 업로드 및 미리보기</h2>
<p>서버 전송 없이 로컬에서 이미지를 읽어옵니다.</p>
</div>
<div class="upload-container">
<label for="fileInput" class="upload-btn">
<i class="ph-duotone ph-upload-simple"></i> 파일 선택하기
</label>
<input type="file" id="fileInput" accept="image/*" style="display: none;">
<p class="file-info" id="fileInfo">선택된 파일이 없습니다.</p>
</div>
<div class="preview-container" id="previewContainer">
<div class="placeholder" id="placeholder">
<i class="ph-duotone ph-image"></i>
<p>이미지 미리보기 영역</p>
</div>
<img id="previewImage" src="" alt="미리보기" style="display: none;">
</div>
</div>HTML에 정의된 캔버스 태그는 아무것도 그려져 있지 않은 빈 도화지(공간) 역할만 합니다. 스스로 그림을 그릴 수 없습니다.
getContext('2d')를 통해 얻는 객체입니다. 이 붓을 자바스크립트로 조종하여 선 굵기, 색상, 좌표를 설정하고 도화지에 그림을 그립니다.
| 속성 및 메서드 | 설명 |
|---|---|
fillStyle / strokeStyle |
도형의 내부를 채우는 색상(fill)과 테두리의 색상(stroke)을 지정합니다. css의 색상 문자열을 그대로 사용합니다. |
fillRect(x, y, w, h) |
지정된 좌표 (x, y)에서 시작하여 너비 w, 높이 h만큼의 색이 채워진 사각형을 한 번에 그립니다. clearRect()는 특정 영역을 투명하게 지웁니다. |
beginPath() |
새로운 그림(경로)을 시작하겠다고 선언합니다. 이전 도형과 선이 이어지는 것을 방지합니다. |
arc(x, y, r, startAngle, endAngle) |
원이나 호를 그리기 위해 경로를 추가합니다. 각도는 무조건 라디안(Radian)을 사용하며 완전한 원은 Math.PI * 2 입니다. 경로를 추가한 후 마지막에 fill() 이나 stroke()를 호출해야 화면에 나타납니다. |
<div class="canvas-app">
<div class="header">
<h2>Canvas 애니메이션</h2>
<p>클릭하면 파티클이 생성됩니다!</p>
</div>
<div class="canvas-container">
<canvas id="myCanvas"></canvas>
</div>
<div class="controls">
<span id="particleCount">Particles: 0</span>
<button id="clearBtn">화면 지우기</button>
</div>
</div>사용자의 위치는 민감한 정보입니다. 자바스크립트가 브라우저에게 나침반(API)을 빌려달라고 요청하면, 브라우저는 반드시 사용자에게 "허용하시겠습니까?"라는 열쇠를 요구합니다.
허용을 받으면 스마트폰의 GPS 칩셋이나 PC가 연결된 Wi-Fi, IP 주소를 기반으로 삼각측량을 하여 위도/경도 데이터 세트를 가져옵니다.
| API 형태 | 역할 및 설명 |
|---|---|
getCurrentPosition(success, error, options) |
현재 시점의 사용자 위치를 단 한 번 가져옵니다. 비동기로 동작하며 성공 시 success 콜백에 Position 객체를 전달합니다. |
watchPosition(success, error, options) |
사용자가 이동할 때마다 위치 변경을 지속적으로 추적하여 콜백을 실행합니다. (예: 내비게이션 앱) |
position.coords (반환 객체 속성) |
성공 콜백으로 반환되는 핵심 데이터입니다. latitude(위도), longitude(경도), accuracy(오차 반경 m) 등의 정보를 포함합니다. |
<div class="geo-app">
<div class="header">
<h2>현재 위치 추적기</h2>
<p>Geolocation API를 사용하여 좌표를 가져옵니다.</p>
</div>
<div class="content">
<button id="getLocationBtn" class="action-btn">
<i class="ph-duotone ph-crosshair"></i> 내 위치 찾기
</button>
<div id="loading" class="loading" style="display: none;">
위치 정보를 요청 중입니다... (권한을 허용해 주세요)
</div>
<div id="resultCard" class="result-card" style="display: none;">
<div class="coordinate">
<span class="label">위도 (Latitude)</span>
<span id="latValue" class="value">--</span>
</div>
<div class="coordinate">
<span class="label">경도 (Longitude)</span>
<span id="lngValue" class="value">--</span>
</div>
<div class="coordinate">
<span class="label">정확도 (Accuracy)</span>
<span id="accValue" class="value">--</span>
</div>
</div>
<div id="errorBox" class="error-box" style="display: none;"></div>
</div>
</div><div class="container">
<h3>Page Visibility API</h3>
<p id="status">현재 상태: <span class="active">활성 (탭을 보고 있음)</span></p>
<div id="log"></div>
</div><div class="dnd-container">
<div id="draggable" draggable="true" class="box">드래그 하세요!</div>
<div id="dropzone" class="zone">이곳에 드롭하세요</div>
</div>버튼 클릭부터 운영체제의 공유 팝업이 뜨기까지의 흐름도입니다.
Web Share API가 제공하는 핵심 메서드입니다.
| 메서드 | 설명 |
|---|---|
navigator.share(data) |
제공된 데이터 객체(title, text, url 등)를 네이티브 공유 다이얼로그로 전달합니다. Promise를 반환합니다. |
navigator.canShare(data) |
주어진 데이터가 현재 브라우저/기기 환경에서 공유 가능한지 여부를 boolean으로 반환합니다. (공유 시도 전에 검사 용도로 사용) |
navigator.share()에 전달하는 데이터 객체의 구성 요소입니다. 최소 하나 이상의 속성이 포함되어야 합니다.
| 속성명 | 타입 | 설명 |
|---|---|---|
title |
string |
공유할 문서나 콘텐츠의 제목입니다. (OS에 따라 무시될 수도 있습니다.) |
text |
string |
공유할 핵심 텍스트나 설명 메시지입니다. |
url |
string |
공유할 링크(URL) 주소입니다. 보통 페이지 전체를 공유할 때 사용합니다. |
files |
File[] |
공유할 파일들의 배열입니다. 이미지 파일이나 문서 등을 공유할 때 사용됩니다. |
<div class="share-container">
<h3>Web Share API</h3>
<button id="shareBtn" class="btn">🚀 콘텐츠 공유하기</button>
<p id="shareLog"></p>
</div><video>와 <audio> 태그는 브라우저 내장(Native) 재생 기능을 지원합니다. 하지만 실무에서는 제공되는 기본 UI 대신, JavaScript Media API를 제어하여 넷플릭스나 유튜브처럼 브랜드 디자인이 적용된 자체 커스텀 플레이어를 제작합니다.currentTime), 전체 재생 시간(duration), 버퍼링 상태, 재생 속도 등 비디오의 모든 상태를 스크립트로 조작하고 이벤트를 감지할 수 있습니다.
브라우저 기본 UI를 숨기고 JS로 HTML 버튼과 비디오를 연결하는 방식입니다.
미디어 요소의 현재 상태를 읽거나 설정할 수 있는 속성들입니다.
| 속성명 | 타입 | 읽기/쓰기 | 설명 |
|---|---|---|---|
currentTime |
Number | 읽기/쓰기 | 현재 재생 중인 시간(초 단위)을 나타냅니다. 값을 할당하여 원하는 시점으로 탐색(Seek)할 수 있습니다. |
duration |
Number | 읽기 전용 | 미디어의 전체 길이를 초 단위로 반환합니다. 메타데이터가 로드되지 않았다면 NaN을 반환합니다. |
volume |
Number | 읽기/쓰기 | 볼륨 크기를 0.0(음소거)부터 1.0(최대) 사이의 값으로 설정하거나 반환합니다. |
muted |
Boolean | 읽기/쓰기 | 음소거 여부를 설정합니다. (true 설정 시 소리가 나지 않음) |
paused |
Boolean | 읽기 전용 | 현재 미디어가 일시정지 상태인지(재생 중이 아닌지)를 반환합니다. |
ended |
Boolean | 읽기 전용 | 재생이 완전히 끝났는지를 반환합니다. |
playbackRate |
Number | 읽기/쓰기 | 재생 속도를 설정합니다. (예: 1.0은 정상 속도, 2.0은 2배속) |
src |
String | 읽기/쓰기 | 미디어 파일의 경로(URL)를 가져오거나 동적으로 변경합니다. |
스크립트를 통해 미디어를 직접 조작하는 함수들입니다.
| 메서드명 | 설명 |
|---|---|
play() |
미디어 재생을 시작합니다. 이 메서드는 Promise를 반환하므로, 자동 재생이 차단된 경우 에러를 캐치할 수 있습니다. |
pause() |
미디어 재생을 일시정지합니다. (stop 메서드는 없으며, pause() 후 currentTime = 0으로 정지를 구현합니다.) |
load() |
미디어 요소가 네트워크에서 미디어 데이터를 다시 처음부터 로드하도록 강제합니다. src를 변경한 후에 호출해야 합니다. |
canPlayType(type) |
브라우저가 해당 MIME 타입(예: 'video/mp4')을 재생할 수 있는지 검사합니다. "probably", "maybe", 또는 ""(빈 문자열)을 반환합니다. |
미디어의 상태가 변할 때 발생하는 이벤트들입니다. addEventListener를 통해 감지합니다.
| 이벤트명 | 발생 시점 및 활용 |
|---|---|
timeupdate |
currentTime이 바뀔 때마다 연속적으로 발생합니다. (보통 1초에 4~5회) 진행률 바(Progress bar)를 업데이트할 때 가장 많이 사용됩니다. |
play / pause |
재생이 시작되거나 일시정지될 때 발생합니다. 재생/일시정지 버튼의 아이콘을 변경할 때 사용합니다. |
ended |
미디어 재생이 끝까지 도달했을 때 발생합니다. 다음 영상으로 넘어가거나 재생 버튼을 리셋할 때 유용합니다. |
loadedmetadata |
미디어의 메타데이터(전체 길이 duration, 해상도 등)를 성공적으로 읽어왔을 때 발생합니다. 총 재생 시간을 화면에 표시할 수 있는 첫 번째 시점입니다. |
<div class="media-container">
<h3>Video & Audio API</h3>
<video id="myVideo" width="100%" poster="https://via.placeholder.com/640x360/1e293b/60a5fa?text=HTML5+Video">
<source src="https://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4">
브라우저가 비디오를 지원하지 않습니다.
</video>
<div class="controls">
<button id="playBtn" class="ctrl-btn">▶ Play</button>
<button id="pauseBtn" class="ctrl-btn">⏸ Pause</button>
<button id="muteBtn" class="ctrl-btn">🔊 Mute</button>
</div>
</div>사용자의 권한을 요청하고 승인을 받은 후 실제 바탕화면에 알림을 노출하는 시퀀스입니다.
new Notification(title, options)에서 설정할 수 있는 주요 시각적 속성들입니다.
| 옵션명 | 설명 |
|---|---|
body |
알림의 본문 텍스트 내용을 설정합니다. |
icon |
알림 타이틀 옆에 작게 표시될 아이콘 이미지의 URL입니다. |
image |
알림 하단에 큼직하게 들어갈 이미지의 URL입니다. (OS 지원 여부에 따라 다름) |
badge |
(모바일) 알림이 올 때 표시될 배지 아이콘의 URL입니다. |
tag |
알림을 식별하는 고유 태그. 동일한 tag를 가진 알림은 이전 알림을 덮어씁니다. |
data |
알림과 함께 저장해 둘 임의의 데이터 객체. 클릭 이벤트 등에서 event.target.data로 읽어올 수 있습니다. |
| 메서드/이벤트 | 설명 |
|---|---|
Notification.permission |
정적 속성. 현재 알림 권한 상태를 반환합니다. ('granted', 'denied', 'default') |
Notification.requestPermission() |
사용자에게 알림 표시 권한을 요청합니다. 권한 상태 문자열을 resolve하는 Promise를 반환합니다. |
notification.close() |
화면에 떠 있는 특정 알림 인스턴스를 스크립트로 즉시 닫습니다. |
onclick |
사용자가 바탕화면의 알림 창을 클릭했을 때 발생합니다. 보통 해당 탭을 포커스(window.focus())하거나 특정 URL로 이동시키는 처리를 합니다. |
onclose |
사용자가 직접 알림의 'X' 버튼을 눌러 닫거나, OS 자체 타이머에 의해 닫혔을 때 발생합니다. |
<div class="noti-container">
<h3>Web Notifications API</h3>
<p>브라우저 외부로 시스템 푸시 알림을 보냅니다.</p>
<button id="reqBtn" class="btn">권한 요청</button>
<button id="sendBtn" class="btn" disabled>알림 보내기</button>
<p id="log" style="color: #f43f5e; margin-top: 1rem; font-weight: bold;"></p>
</div>