diff --git a/files/ko/learn/javascript/building_blocks/event_bubbling/index.md b/files/ko/learn/javascript/building_blocks/event_bubbling/index.md new file mode 100644 index 00000000000000..c1fdd5a269d22f --- /dev/null +++ b/files/ko/learn/javascript/building_blocks/event_bubbling/index.md @@ -0,0 +1,417 @@ +--- +title: 이벤트 버블링 +slug: Learn/JavaScript/Building_blocks/Event_bubbling +l10n: + sourceCommit: bc0d0d1ef796435e969f6d65c7e5d3c08f4023aa +--- + +{{LearnSidebar}}{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Events","Learn/JavaScript/Building_blocks/Image_gallery", "Learn/JavaScript/Building_blocks")}} + +웹 페이지는 제목, 텍스트 단락, 이미지, 버튼 등 "요소"로 구성되어 있으며 이러한 요소에 발생하는 이벤트를 수신할 수 있다는 것을 살펴보았습니다. 예를 들어, 버튼에 수신기를 추가하면 사용자가 버튼을 클릭했을 때 실행됩니다. + +또한 이러한 요소가 서로 "중첩"될 수 있다는 것을 보았습니다. 예를 들어, {{htmlelement("button")}}은 {{htmlelement("div")}} 요소 안에 놓일 수 있습니다. 이 때 `
` 요소를 "부모" 요소라고 부르고 ` +
+

+```
+
+여기서 버튼은 다른 요소인 {{HTMLElement("div")}} 안에 있습니다. 이 `
` 요소는 내부에 포함된 요소의 **부모**라고 합니다. 부모에 클릭 이벤트 처리기를 추가한 다음 버튼을 클릭하면 어떻게 될까요? + +```js +const output = document.querySelector("#output"); +function handleClick(e) { + output.textContent += `${e.currentTarget.tagName} 요소를 클릭했습니다.\n`; +} + +const container = document.querySelector("#container"); +container.addEventListener("click", handleClick); +``` + +{{ EmbedLiveSample('Setting a listener on a parent element', '100%', 200, "", "") }} + +사용자가 버튼을 클릭하면 부모가 클릭 이벤트를 방출하는 것을 볼 수 있습니다. + +```plain +DIV 요소를 클릭했습니다. +``` + +버튼이 `
` 안에 있으므로 버튼을 클릭하면 암시적으로 버튼 안에 있는 요소도 클릭하게 됩니다. + +### 버블링 예제 + +버튼과 부모 "둘 다" 이벤트 수신기를 추가하면 어떻게 될까요? + +```html + +
+ +
+

+
+```
+
+버튼과 부모(`
`), 그리고 두 요소를 모두 포함하는 {{HTMLElement("body")}} 요소에 클릭 이벤트 처리기를 추가해 보겠습니다. + +```js +const output = document.querySelector("#output"); +function handleClick(e) { + output.textContent += `${e.currentTarget.tagName} 요소를 클릭했습니다.\n`; +} + +const container = document.querySelector("#container"); +const button = document.querySelector("button"); + +document.body.addEventListener("click", handleClick); +container.addEventListener("click", handleClick); +button.addEventListener("click", handleClick); +``` + +{{ EmbedLiveSample('Bubbling example', '100%', 200, "", "") }} + +사용자가 버튼을 클릭하면 세 요소 모두 클릭 이벤트를 방출하는 것을 볼 수 있습니다. + +```plain +BUTTON 요소를 클릭했습니다. +DIV 요소를 클릭했습니다. +BODY 요소를 클릭했습니다. +``` + +이 경우는 다음과 같습니다. + +- 버튼 클릭이 먼저 일어납니다. +- 그 다음에 부모(`
` 요소) 클릭이 일어납니다. +- 그리고 `
` 요소의 부모(`` 요소) 클릭이 일어납니다. + +이를 이벤트가 클릭한 가장 안쪽의 요소에서 **상위로 버블링**된다고 설명할 수 있습니다. + +이 동작은 유용할 수도 있고 예상치 못한 문제를 일으킬 수도 있습니다. 다음 섹션에서는 이로 인해 발생하는 문제를 살펴보고 해결책을 찾아보겠습니다. + +### 동영상 플레이어 예제 + +이 예제에서 페이지에 처음에는 숨겨져있는 동영상과 "동영상 표시"라는 버튼이 있습니다. 우리는 다음과 같은 상호작용을 원합니다. + +- 사용자가 "동영상 표시" 버튼을 클릭하면 동영상이 포함된 상자를 표시하지만 재생하지는 않습니다. +- 사용자가 동영상을 클릭하면 재생합니다. +- 사용자가 동영상 외부의 상자 어딘가를 클릭하면 상자를 숨깁니다. + +HTML은 다음과 같습니다. + +```html + + + +``` + +HTML에는 다음이 포함됩니다. + +- ` + + +``` + +```css hidden +div { + width: 100%; + height: 100%; + background-color: #eee; +} + +.hidden { + display: none; +} + +div video { + padding: 40px; + display: block; + width: 400px; + margin: 40px auto; +} +``` + +## 이벤트 캡처 + +이벤트 전파의 또 다른 형태로 "이벤트 캡처"가 있습니다. 이것은 이벤트 버블링과 비슷하지만 순서가 반대입니다. 즉, 이벤트가 대상의 가장 안쪽의 대상 요소에서 발생해서 그 다음으로 중첩이 적은 요소순으로 전파되는게 아니라, 반대로 "가장 적게 중첩된" 요소에서 발생해서 그 다음으로 중첩이 많은 요소순으로 대상에 도달할 때까지 전파됩니다. + +이벤트 캡처는 기본적으로 비활성화되어 있습니다. 활성화하려면 `addEventListener()`에서 `capture` 옵션을 전달해야 합니다. + +이 예제는 `capture` 옵션을 사용한다는 점을 제외하면 앞서 본 [버블링 예제](#버블링_예제)와 동일합니다. + +```html + +
+ +
+

+
+```
+
+```js
+const output = document.querySelector("#output");
+function handleClick(e) {
+  output.textContent += `${e.currentTarget.tagName} 요소를 클릭했습니다.\n`;
+}
+
+const container = document.querySelector("#container");
+const button = document.querySelector("button");
+
+document.body.addEventListener("click", handleClick, { capture: true });
+container.addEventListener("click", handleClick, { capture: true });
+button.addEventListener("click", handleClick);
+```
+
+{{ EmbedLiveSample('Event capture', '100%', 200, "", "") }}
+
+이 경우 메시지 순서는 반대입니다. `` 이벤트 처리기가 먼저 실행되고, 그 다음에 `
` 이벤트 처리기가 실행되고, 그 다음에 ` +
+

+
+```
+
+JavaScript는 `target`과 `currentTarget`을 모두 로깅하는것 외에는 거의 같습니다.
+
+```js
+const output = document.querySelector("#output");
+function handleClick(e) {
+  const logTarget = `Target: ${e.target.tagName}`;
+  const logCurrentTarget = `Current target: ${e.currentTarget.tagName}`;
+  output.textContent += `${logTarget}, ${logCurrentTarget}\n`;
+}
+
+const container = document.querySelector("#container");
+const button = document.querySelector("button");
+
+document.body.addEventListener("click", handleClick);
+container.addEventListener("click", handleClick);
+button.addEventListener("click", handleClick);
+```
+
+버튼을 클릭했을 때, 이벤트 처리기가 버튼 자체나 `
` 또는 `` 에 연결되어 있어도 `target` 은 항상 버튼 요소라는 점을 주의하세요. 그러나 `currentTarget`은 현재 실행중인 이벤트 처리기의 요소로 식별됩니다. + +{{embedlivesample("target and currentTarget")}} + +`target` 속성은 위의 [이벤트 위임](#이벤트_위임) 예제처럼 이벤트 위임에서 자주 사용합니다. + +## 스킬 테스트! + +이 문서의 마지막까지 왔습니다. 그런데 가장 중요한 정보를 기억하고 있나요? 계속하기 전에 이 정보를 기억했는지 확인하려면 [스킬 테스트: 이벤트](/ko/docs/Learn/JavaScript/Building_blocks/Test_your_skills:_Events)를 참조하세요. + +## 요약 + +이제 이 초기 단계에서 웹 이벤트에 대해 알아야 할 모든 것을 알게 되었을 것입니다. +앞서 언급했듯이 이벤트는 코어 JavaScript의 일부가 아니며 브라우저 웹 API에서 정의되어 있습니다. + +또한 웹 API에서부터 브라우저 WebExtensions, Node.js(서버 측 JavaScript)와 같은 다른 영역에 이르기까지 JavaScript를 사용하는 맥락에 따라 다양한 이벤트 모델이 있다는 것을 이해하는 것이 중요합니다. +지금 당장 이 모든 영역을 이해할 것으로 기대하지는 않지만 웹 개발을 배우면서 이벤트의 기본을 이해하는 데 확실히 도움이 됩니다. + +> [!NOTE] +> 진행중에 막혔다면 [커뮤니케이션 채널](/ko/docs/MDN/Community/Communication_channels)에서 도움을 요청하세요. + +## 같이 보기 + +- [domevents.dev](https://domevents.dev/) — 탐색을 통해 DOM 이벤트 시스템의 동작에 대해 학습할 수 있는 매우 유용한 대화형 놀이터 앱입니다. +- [이벤트 참고서](/ko/docs/Web/Events) +- [이벤트 순서](https://www.quirksmode.org/js/events_order.html) (캡처링과 버블링에 대한 논의) — 피터-폴 코흐가 매우 자세하게 설명한 글입니다. + +{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Events","Learn/JavaScript/Building_blocks/Image_gallery", "Learn/JavaScript/Building_blocks")}}