From 9fc5ddc6db93cd87e87b393b8017ce9482a4966e Mon Sep 17 00:00:00 2001 From: Jiyeon Date: Sun, 17 May 2026 17:51:40 +0900 Subject: [PATCH] =?UTF-8?q?[=EB=AC=B8=EC=84=9C]=20C27=20=EC=B6=A9=EB=8F=8C?= =?UTF-8?q?=20=EB=B0=8F=20=EB=B2=88=EC=97=AD=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../1-mouse-events-basics/article.md | 33 -- .../article.md | 197 +++++----- .../4-mouse-drag-and-drop/article.md | 39 -- .../6-pointer-events/article.md | 358 +++++++----------- .../7-keyboard-events/article.md | 172 ++++----- 2-ui/3-event-details/8-onscroll/article.md | 32 +- 2-ui/5-loading/03-onload-onerror/article.md | 126 +++--- 7 files changed, 399 insertions(+), 558 deletions(-) diff --git a/2-ui/3-event-details/1-mouse-events-basics/article.md b/2-ui/3-event-details/1-mouse-events-basics/article.md index 2ec6799b3a..fe88929d1a 100644 --- a/2-ui/3-event-details/1-mouse-events-basics/article.md +++ b/2-ui/3-event-details/1-mouse-events-basics/article.md @@ -1,9 +1,4 @@ -<<<<<<< HEAD # 마우스 이벤트 -======= - -# Mouse events ->>>>>>> upstream/master 이번 챕터에선 마우스 이벤트와 마우스 이벤트 객체의 프로퍼티에 대해 자세히 다루겠습니다. @@ -44,15 +39,9 @@ ```online 아래 버튼을 클릭 또는 더블클릭해 실제 마우스 버튼을 클릭했을 때 어떤 일이 발생하는지 알아봅시다. -<<<<<<< HEAD 모든 마우스 이벤트가 버튼 아래 창에 기록되는데, 이벤트 발생 간격이 1초 이상일 때는 이벤트 사이에 가로 선이 추가되도록 해놓았습니다. 이벤트 이름 옆엔 어떤 마우스 버튼이 이벤트를 발생시켰는지를 알려주는 `button` 프로퍼티도 보이는데, `button` 프로퍼티에 대한 내용은 바로 아래에서 설명하도록 하겠습니다. -======= -On the teststand below, all mouse events are logged, and if there is more than a 1 second delay between them, they are separated by a horizontal rule. - -Also, we can see the `button` property that allows us to detect the mouse button; it's explained below. ->>>>>>> upstream/master
``` @@ -63,37 +52,21 @@ Also, we can see the `button` property that allows us to detect the mouse button `click` 이벤트는 마우스 왼쪽 버튼을, `contextmenu` 이벤트는 마우스 오른쪽 버튼을 눌렀을 때 발생하기 때문에 `click`과 `contextmenu` 이벤트를 다룰 땐 보통 `button` 프로퍼티를 사용하지 않습니다. -<<<<<<< HEAD 반면 `mousedown`이벤트나 `mouseup` 이벤트를 다룰 땐 해당 이벤트의 핸들러에 `event.button`을 명시해 줘야 할 수 있습니다. 이 이벤트들은 마우스 버튼 어디에서나 발생할 수 있는데 `button` 프로퍼티를 사용해야 정확히 어떤 버튼에서 이벤트가 발생했는지 알 수 있기 때문입니다. -======= -On the other hand, `mousedown` and `mouseup` handlers may need `event.button`, because these events trigger on any button, so `button` allows to distinguish between "right-mousedown" and "left-mousedown". ->>>>>>> upstream/master 주요 `event.button` 프로퍼티 값을 정리하면 다음과 같습니다. | 버튼 | `event.button` | |--------------|----------------| -<<<<<<< HEAD | 왼쪽(주요 버튼) | 0 | | 가운데(보조 버튼) | 1 | | 오른쪽 (두 번째 버튼) | 2 | | X1(뒤로 가기 버튼) | 3 | | X2(앞으로 가기 버튼) | 4 | -======= -| Left button (primary) | 0 | -| Middle button (auxiliary) | 1 | -| Right button (secondary) | 2 | -| X1 button (back) | 3 | -| X2 button (forward) | 4 | ->>>>>>> upstream/master 상당수의 마우스는 왼쪽, 오른쪽 버튼만 가지고 있기 때문에 이 마우스들이 만들어내는 `event.button` 값은 `0`이나 `2`가 됩니다. 터치를 지원하는 기기들도 사람이 해당 기기를 터치했을 때 유사한 이벤트를 만듭니다. -<<<<<<< HEAD 참고로 `buttons`라는 프로퍼티도 있는데, 이 프로퍼티는 여러 개의 버튼을 한꺼번에 눌렀을 때 해당 버튼들에 대한 정보를 정수 형태로 저장해 줍니다. 실무에서 `buttons` 프로퍼티를 만날 일은 극히 드물긴 하지만 혹시라도 필요하다면[MDN](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons)에서 확인해보시길 바랍니다. -======= -Also there's `event.buttons` property that has all currently pressed buttons as an integer, one bit per button. In practice this property is very rarely used, you can find details at [MDN](mdn:/api/MouseEvent/buttons) if you ever need it. ->>>>>>> upstream/master ```warn header="역사의 뒤안길로 사라진 `event.which`" 오래된 코드를 보다 보면 `event.which`라는 프로퍼티를 발견할 수 있습니다. `event.which` 프로퍼티는 어떤 버튼을 클릭했는지 알려주는 비표준 프로퍼티로 다음과 같은 값을 가집니다. @@ -181,15 +154,9 @@ Windows와 Linux는 `key:Alt`, `key:Shift`, `key:Ctrl` 키를 지원합니다. ## mousedown 이벤트와 선택 막기 -<<<<<<< HEAD 글자 위에서 마우스를 더블클릭하면 글자가 선택되는데, 이런 기본 동작이 사용자 경험을 해칠 때가 있습니다. `dblclick` 이벤트가 발생하면 얼럿 창을 띄우고 싶다고 가정해 봅시다. 제대로 코드를 작성했음에도 불구하고 핸들러가 실행되는 동시에 글자가 선택되는 불필요한 부수효과가 발생하였습니다. -======= -Double mouse click has a side effect that may be disturbing in some interfaces: it selects text. - -For instance, double-clicking on the text below selects it in addition to our handler: ->>>>>>> upstream/master ```html autorun height=50 이곳을 더블클릭해주세요. diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/article.md b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/article.md index d409c3f127..9a823fcbbd 100644 --- a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/article.md +++ b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/article.md @@ -1,221 +1,224 @@ -# Moving the mouse: mouseover/out, mouseenter/leave +# mouseover·mouseout과 mouseenter·mouseleave -Let's dive into more details about events that happen when the mouse moves between elements. +마우스가 요소 사이를 이동할 때 발생하는 이벤트를 자세히 살펴보겠습니다. -## Events mouseover/mouseout, relatedTarget +## mouseover·mouseout 이벤트와 relatedTarget -The `mouseover` event occurs when a mouse pointer comes over an element, and `mouseout` -- when it leaves. +`mouseover` 이벤트는 마우스 포인터가 요소 위로 올라올 때 발생하고, `mouseout` 이벤트는 요소를 떠날 때 발생합니다. ![](mouseover-mouseout.svg) -These events are special, because they have property `relatedTarget`. This property complements `target`. When a mouse leaves one element for another, one of them becomes `target`, and the other one - `relatedTarget`. +이 이벤트들이 특별한 이유는 `relatedTarget` 프로퍼티가 있기 때문입니다. 이 프로퍼티는 `target`을 보완합니다. 마우스가 한 요소에서 다른 요소로 이동할 때 둘 중 하나는 `target`이 되고, 다른 하나는 `relatedTarget`이 됩니다. -For `mouseover`: +`mouseover`의 경우는 다음과 같습니다. -- `event.target` -- is the element where the mouse came over. -- `event.relatedTarget` -- is the element from which the mouse came (`relatedTarget` -> `target`). +- `event.target` -- 마우스가 올라간 요소 +- `event.relatedTarget` -- 마우스가 떠나온 요소 (`relatedTarget` -> `target`) -For `mouseout` the reverse: +`mouseout`의 경우는 반대입니다. -- `event.target` -- is the element that the mouse left. -- `event.relatedTarget` -- is the new under-the-pointer element, that mouse left for (`target` -> `relatedTarget`). +- `event.target` -- 마우스가 떠난 요소 +- `event.relatedTarget` -- 마우스가 이동해 새로 포인터 아래에 놓인 요소 (`target` -> `relatedTarget`) ```online -In the example below each face and its features are separate elements. When you move the mouse, you can see mouse events in the text area. +아래 예시에서는 얼굴과 눈, 입 같은 각 부분이 모두 별개의 요소입니다. 마우스를 움직이면 텍스트 영역에서 마우스 이벤트를 확인할 수 있습니다. -Each event has the information about both `target` and `relatedTarget`: +각 이벤트에는 `target`과 `relatedTarget` 정보가 모두 담겨 있습니다. [codetabs src="mouseoverout" height=280] ``` -```warn header="`relatedTarget` can be `null`" -The `relatedTarget` property can be `null`. +```warn header="`relatedTarget`이 `null`인 경우" +`relatedTarget` 프로퍼티는 `null`이 될 수 있습니다. -That's normal and just means that the mouse came not from another element, but from out of the window. Or that it left the window. +이는 정상적인 동작이며, 마우스가 다른 요소에서 온 것이 아니라 윈도우 밖에서 들어왔거나 윈도우를 떠났다는 뜻입니다. -We should keep that possibility in mind when using `event.relatedTarget` in our code. If we access `event.relatedTarget.tagName`, then there will be an error. -``` +코드에서 `event.relatedTarget`을 사용할 때는 이 가능성을 염두에 두어야 합니다. `event.relatedTarget.tagName`에 접근하면 에러가 발생합니다. + +```` -## Skipping elements +## 요소 건너뛰기 -The `mousemove` event triggers when the mouse moves. But that doesn't mean that every pixel leads to an event. +`mousemove` 이벤트는 마우스가 움직일 때 발생합니다. 그렇다고 모든 픽셀마다 이벤트가 발생하는 것은 아닙니다. -The browser checks the mouse position from time to time. And if it notices changes then triggers the events. +브라우저는 마우스 위치를 주기적으로 확인합니다. 변화를 감지하면 이벤트를 발생시킵니다. -That means that if the visitor is moving the mouse very fast then some DOM-elements may be skipped: +따라서 사용자가 마우스를 매우 빠르게 움직이면 일부 DOM 요소를 건너뛸 수 있습니다. ![](mouseover-mouseout-over-elems.svg) -If the mouse moves very fast from `#FROM` to `#TO` elements as painted above, then intermediate `
` elements (or some of them) may be skipped. The `mouseout` event may trigger on `#FROM` and then immediately `mouseover` on `#TO`. +위 그림처럼 마우스가 `#FROM` 요소에서 `#TO` 요소로 매우 빠르게 이동하면, 중간에 있는 `
` 요소 또는 그 일부를 건너뛸 수 있습니다. `#FROM`에서 `mouseout` 이벤트가 발생하고 곧바로 `#TO`에서 `mouseover`가 발생할 수 있습니다. -That's good for performance, because there may be many intermediate elements. We don't really want to process in and out of each one. +중간 요소가 많을 수 있기 때문에 성능 면에서는 좋습니다. 각 요소에 들어가고 나오는 과정을 일일이 처리하고 싶지는 않으니까요. -On the other hand, we should keep in mind that the mouse pointer doesn't "visit" all elements along the way. It can "jump". +반면 마우스 포인터가 이동 경로에 있는 모든 요소를 '방문'하지 않을 수 있다는 점도 기억해야 합니다. 포인터는 '점프'할 수 있습니다. -In particular, it's possible that the pointer jumps right inside the middle of the page from out of the window. In that case `relatedTarget` is `null`, because it came from "nowhere": +특히 윈도우 밖에서 페이지 한가운데로 포인터가 바로 점프하는 것도 가능합니다. 이 경우 포인터가 '어디에서도' 오지 않았으므로 `relatedTarget`은 `null`입니다. ![](mouseover-mouseout-from-outside.svg) ```online -You can check it out "live" on a teststand below. +아래 테스트 환경에서 직접 확인할 수 있습니다. -Its HTML has two nested elements: the `
` is inside the `
`. If you move the mouse fast over them, then maybe only the child div triggers events, or maybe the parent one, or maybe there will be no events at all. +HTML에는 중첩된 두 요소가 있습니다. `
`가 `
` 안에 있습니다. 이 요소들 위에서 마우스를 빠르게 움직이면 자식 div에서만 이벤트가 발생하거나, 부모 요소에서만 발생하거나, 아예 이벤트가 발생하지 않을 수도 있습니다. -Also move the pointer into the child `div`, and then move it out quickly down through the parent one. If the movement is fast enough, then the parent element is ignored. The mouse will cross the parent element without noticing it. +포인터를 자식 `div` 안으로 이동한 다음, 부모 요소를 지나 아래쪽으로 빠르게 움직여 보세요. 움직임이 아주 빠르면 부모 요소는 무시됩니다. 마우스가 부모 요소를 알아채지 못한 채 지나가게 됩니다. [codetabs height=360 src="mouseoverout-fast"] -``` +```` -```smart header="If `mouseover` triggered, there must be `mouseout`" -In case of fast mouse movements, intermediate elements may be ignored, but one thing we know for sure: if the pointer "officially" entered an element (`mouseover` event generated), then upon leaving it we always get `mouseout`. -``` +```smart header="`mouseover`가 발생했다면 반드시 `mouseout`도 발생합니다" +마우스를 빠르게 움직이면 중간 요소가 무시될 수 있지만 한 가지는 확실합니다. 포인터가 어떤 요소에 '공식적으로' 들어갔다면(`mouseover` 이벤트 발생), 그 요소를 떠날 때는 항상 `mouseout`이 발생합니다. -## Mouseout when leaving for a child +```` -An important feature of `mouseout` -- it triggers, when the pointer moves from an element to its descendant, e.g. from `#parent` to `#child` in this HTML: +## 자식 요소로 이동할 때의 mouseout 이벤트 + +`mouseout`에는 중요한 특징이 있습니다. 포인터가 요소에서 그 후손 요소로 이동할 때도 발생한다는 점입니다. 예를 들어 아래 HTML처럼 `#parent`에서 `#child`로 이동할 때도 발생합니다. ```html
...
-``` +```` -If we're on `#parent` and then move the pointer deeper into `#child`, we get `mouseout` on `#parent`! +`#parent` 위에 있다가 포인터를 `#child` 안쪽으로 더 깊이 이동하면 `#parent`에서 `mouseout`이 발생합니다! ![](mouseover-to-child.svg) -That may seem strange, but can be easily explained. +이상해 보일 수 있지만 쉽게 설명할 수 있습니다. -**According to the browser logic, the mouse cursor may be only over a *single* element at any time -- the most nested one and top by z-index.** +**브라우저 로직에 따르면 마우스 커서는 어느 순간이든 _단 하나_의 요소 위에만 있을 수 있습니다. 가장 깊이 중첩되어 있고 z-index 기준으로 맨 위에 있는 요소입니다.** -So if it goes to another element (even a descendant), then it leaves the previous one. +따라서 다른 요소로 이동하면, 설령 그 요소가 후손 요소라 해도 이전 요소를 떠난 것으로 처리됩니다. -Please note another important detail of event processing. +이벤트 처리와 관련해 한 가지 더 중요한 세부 사항을 짚고 넘어가겠습니다. -The `mouseover` event on a descendant bubbles up. So, if `#parent` has `mouseover` handler, it triggers: +후손 요소에서 발생한 `mouseover` 이벤트는 버블링됩니다. 따라서 `#parent`에 `mouseover` 핸들러가 있으면 이 핸들러가 실행됩니다. ![](mouseover-bubble-nested.svg) ```online -You can see that very well in the example below: `
` is inside the `
`. There are `mouseover/out` handlers on `#parent` element that output event details. +아래 예시에서 이를 잘 확인할 수 있습니다. `
`가 `
` 안에 있습니다. `#parent` 요소에는 이벤트 세부 정보를 출력하는 `mouseover·mouseout` 핸들러가 있습니다. -If you move the mouse from `#parent` to `#child`, you see two events on `#parent`: -1. `mouseout [target: parent]` (left the parent), then -2. `mouseover [target: child]` (came to the child, bubbled). +마우스를 `#parent`에서 `#child`로 이동하면 `#parent`에서 두 이벤트를 확인할 수 있습니다. +1. `mouseout [target: parent]` (부모를 떠남), 이후 +2. `mouseover [target: child]` (자식으로 이동, 버블링됨) [codetabs height=360 src="mouseoverout-child"] ``` -As shown, when the pointer moves from `#parent` element to `#child`, two handlers trigger on the parent element: `mouseout` and `mouseover`: +위에서 보듯이 포인터가 `#parent` 요소에서 `#child`로 이동하면 부모 요소에서 두 핸들러가 실행됩니다. 바로 `mouseout`과 `mouseover`입니다. ```js -parent.onmouseout = function(event) { - /* event.target: parent element */ +parent.onmouseout = function (event) { + /* event.target: 부모 요소 */ }; -parent.onmouseover = function(event) { - /* event.target: child element (bubbled) */ +parent.onmouseover = function (event) { + /* event.target: 자식 요소 (버블링됨) */ }; ``` -**If we don't examine `event.target` inside the handlers, then it may seem that the mouse pointer left `#parent` element, and then immediately came back over it.** +**핸들러 안에서 `event.target`을 확인하지 않으면 마우스 포인터가 `#parent` 요소를 떠났다가 곧바로 다시 올라온 것처럼 보일 수 있습니다.** -But that's not the case! The pointer is still over the parent, it just moved deeper into the child element. +하지만 실제로는 그렇지 않습니다! 포인터는 여전히 부모 위에 있고, 단지 자식 요소 안쪽으로 더 깊이 이동했을 뿐입니다. -If there are some actions upon leaving the parent element, e.g. an animation runs in `parent.onmouseout`, we usually don't want it when the pointer just goes deeper into `#parent`. +부모 요소를 떠날 때 실행하는 동작이 있다면, 예를 들어 `parent.onmouseout`에서 애니메이션을 실행한다면, 포인터가 단순히 `#parent` 안쪽으로 더 깊이 들어갈 때는 보통 그 동작이 실행되지 않길 원합니다. -To avoid it, we can check `relatedTarget` in the handler and, if the mouse is still inside the element, then ignore such event. +이를 피하려면 핸들러에서 `relatedTarget`을 확인하고, 마우스가 여전히 요소 안에 있다면 해당 이벤트를 무시하면 됩니다. -Alternatively we can use other events: `mouseenter` and `mouseleave`, that we'll be covering now, as they don't have such problems. +또 다른 방법으로는 지금부터 살펴볼 `mouseenter`와 `mouseleave` 이벤트를 사용할 수 있습니다. 이 이벤트에는 이런 문제가 없습니다. -## Events mouseenter and mouseleave +## mouseenter와 mouseleave 이벤트 -Events `mouseenter/mouseleave` are like `mouseover/mouseout`. They trigger when the mouse pointer enters/leaves the element. +`mouseenter·mouseleave` 이벤트는 `mouseover·mouseout`과 비슷합니다. 마우스 포인터가 요소에 들어오거나 요소를 떠날 때 발생합니다. -But there are two important differences: +하지만 중요한 차이점이 두 가지 있습니다. -1. Transitions inside the element, to/from descendants, are not counted. -2. Events `mouseenter/mouseleave` do not bubble. +1. 요소 내부에서 후손 요소로 이동하거나 후손 요소에서 돌아오는 전환은 진입·이탈로 보지 않습니다. +2. `mouseenter·mouseleave` 이벤트는 버블링되지 않습니다. -These events are extremely simple. +이 이벤트들은 매우 단순합니다. -When the pointer enters an element -- `mouseenter` triggers. The exact location of the pointer inside the element or its descendants doesn't matter. +포인터가 요소에 들어오면 `mouseenter`가 발생합니다. 포인터가 요소 안이나 후손 요소의 정확히 어디에 있는지는 중요하지 않습니다. -When the pointer leaves an element -- `mouseleave` triggers. +포인터가 요소를 떠나면 `mouseleave`가 발생합니다. ```online -This example is similar to the one above, but now the top element has `mouseenter/mouseleave` instead of `mouseover/mouseout`. +이 예시는 위 예시와 비슷하지만, 이제 최상위 요소에는 `mouseover·mouseout` 대신 `mouseenter·mouseleave`가 있습니다. -As you can see, the only generated events are the ones related to moving the pointer in and out of the top element. Nothing happens when the pointer goes to the child and back. Transitions between descendants are ignored +보시다시피 생성되는 이벤트는 포인터가 최상위 요소 안팎으로 이동하는 것과 관련된 이벤트뿐입니다. 포인터가 자식 요소로 갔다가 돌아올 때는 아무 일도 발생하지 않습니다. 후손 요소 사이의 전환은 무시됩니다. [codetabs height=340 src="mouseleave"] ``` -## Event delegation +## 이벤트 위임 -Events `mouseenter/leave` are very simple and easy to use. But they do not bubble. So we can't use event delegation with them. +`mouseenter·mouseleave` 이벤트는 매우 단순하고 사용하기 쉽습니다. 하지만 버블링되지 않습니다. 따라서 이벤트 위임을 사용할 수 없습니다. -Imagine we want to handle mouse enter/leave for table cells. And there are hundreds of cells. +테이블 셀에 마우스가 들어가고 나가는 것을 처리하고 싶다고 생각해 봅시다. 셀은 수백 개나 있습니다. -The natural solution would be -- to set the handler on `` and process events there. But `mouseenter/leave` don't bubble. So if such event happens on `
`, then only a handler on that `` is able to catch it. +자연스러운 해결책은 ``에 핸들러를 설정하고 거기서 이벤트를 처리하는 것입니다. 하지만 `mouseenter·mouseleave`는 버블링되지 않습니다. 따라서 `
`에서 이런 이벤트가 발생하면 해당 ``에 있는 핸들러만 이를 처리할 수 있습니다. -Handlers for `mouseenter/leave` on `` only trigger when the pointer enters/leaves the table as a whole. It's impossible to get any information about transitions inside it. +`
`에 등록한 `mouseenter·mouseleave` 핸들러는 포인터가 테이블 전체에 들어오거나 테이블 전체를 떠날 때만 실행됩니다. 테이블 내부에서 일어나는 전환 정보는 얻을 수 없습니다. -So, let's use `mouseover/mouseout`. +그러니 `mouseover·mouseout`을 사용해 봅시다. -Let's start with simple handlers that highlight the element under mouse: +마우스 아래에 있는 요소를 강조하는 간단한 핸들러부터 시작하겠습니다. ```js -// let's highlight an element under the pointer -table.onmouseover = function(event) { +// 포인터 아래에 있는 요소를 강조합니다 +table.onmouseover = function (event) { let target = event.target; - target.style.background = 'pink'; + target.style.background = "pink"; }; -table.onmouseout = function(event) { +table.onmouseout = function (event) { let target = event.target; - target.style.background = ''; + target.style.background = ""; }; ``` ```online -Here they are in action. As the mouse travels across the elements of this table, the current one is highlighted: +실제로 동작하는 모습입니다. 마우스가 이 테이블의 요소 사이를 이동하면 현재 요소가 강조됩니다. [codetabs height=480 src="mouseenter-mouseleave-delegation"] ``` -In our case we'd like to handle transitions between table cells `
`: entering a cell and leaving it. Other transitions, such as inside the cell or outside of any cells, don't interest us. Let's filter them out. +여기서는 테이블 셀 `` 사이의 전환, 즉 셀에 들어가고 셀을 떠나는 동작을 처리하려고 합니다. 셀 내부에서의 이동이나 어떤 셀에도 속하지 않는 곳에서의 이동 같은 다른 전환은 관심 대상이 아닙니다. 걸러내 봅시다. -Here's what we can do: +다음과 같이 할 수 있습니다. -- Remember the currently highlighted `` in a variable, let's call it `currentElem`. -- On `mouseover` -- ignore the event if we're still inside the current ``. -- On `mouseout` -- ignore if we didn't leave the current ``. +- 현재 강조된 ``를 변수에 저장합니다. 이 변수를 `currentElem`이라고 하겠습니다. +- `mouseover`에서는 아직 현재 `` 안에 있다면 이벤트를 무시합니다. +- `mouseout`에서는 현재 ``를 떠나지 않았다면 이벤트를 무시합니다. -Here's an example of code that accounts for all possible situations: +가능한 모든 상황을 고려한 코드 예시는 다음과 같습니다. [js src="mouseenter-mouseleave-delegation-2/script.js"] -Once again, the important features are: -1. It uses event delegation to handle entering/leaving of any `` inside the table. So it relies on `mouseover/out` instead of `mouseenter/leave` that don't bubble and hence allow no delegation. -2. Extra events, such as moving between descendants of `` are filtered out, so that `onEnter/Leave` runs only if the pointer leaves or enters `` as a whole. +중요한 특징을 다시 정리해 보겠습니다. + +1. 테이블 안에 있는 모든 ``의 진입·이탈을 처리하기 위해 이벤트 위임을 사용합니다. 따라서 버블링되지 않아 위임을 사용할 수 없는 `mouseenter·mouseleave` 대신 `mouseover·mouseout`에 의존합니다. +2. ``의 후손 요소 사이를 이동하는 것 같은 추가 이벤트는 걸러냅니다. 따라서 포인터가 `` 전체를 기준으로 떠나거나 들어올 때만 `onEnter·Leave`가 실행됩니다. ```online -Here's the full example with all details: +모든 세부 사항이 포함된 전체 예시입니다. [codetabs height=460 src="mouseenter-mouseleave-delegation-2"] -Try to move the cursor in and out of table cells and inside them. Fast or slow -- doesn't matter. Only `` as a whole is highlighted, unlike the example before. +커서를 테이블 셀 안팎으로, 그리고 셀 내부에서 움직여 보세요. 빠르든 느리든 상관없습니다. 이전 예시와 달리 `` 전체만 강조됩니다. ``` -## Summary +## 요약 -We covered events `mouseover`, `mouseout`, `mousemove`, `mouseenter` and `mouseleave`. +`mouseover`, `mouseout`, `mousemove`, `mouseenter`, `mouseleave` 이벤트를 다뤘습니다. -These things are good to note: +다음 사항을 기억해 두면 좋습니다. -- A fast mouse move may skip intermediate elements. -- Events `mouseover/out` and `mouseenter/leave` have an additional property: `relatedTarget`. That's the element that we are coming from/to, complementary to `target`. +- 마우스를 빠르게 움직이면 중간 요소를 건너뛸 수 있습니다. +- `mouseover·mouseout`과 `mouseenter·mouseleave` 이벤트에는 `relatedTarget`이라는 추가 프로퍼티가 있습니다. 이 프로퍼티는 `target`을 보완하며, 마우스가 떠나온 요소나 이동해 가는 요소를 가리킵니다. -Events `mouseover/out` trigger even when we go from the parent element to a child element. The browser assumes that the mouse can be only over one element at one time -- the deepest one. +`mouseover·mouseout` 이벤트는 부모 요소에서 자식 요소로 이동할 때도 발생합니다. 브라우저는 마우스가 한 번에 하나의 요소, 즉 가장 깊이 중첩된 요소 위에만 있을 수 있다고 가정합니다. -Events `mouseenter/leave` are different in that aspect: they only trigger when the mouse comes in and out the element as a whole. Also they do not bubble. +`mouseenter·mouseleave` 이벤트는 이 점에서 다릅니다. 마우스가 요소 전체를 기준으로 들어오고 나갈 때만 발생합니다. 또한 버블링되지 않습니다. diff --git a/2-ui/3-event-details/4-mouse-drag-and-drop/article.md b/2-ui/3-event-details/4-mouse-drag-and-drop/article.md index e20f93bd34..664069e943 100644 --- a/2-ui/3-event-details/4-mouse-drag-and-drop/article.md +++ b/2-ui/3-event-details/4-mouse-drag-and-drop/article.md @@ -18,16 +18,11 @@ 2. 이후 `mousemove`에서 `position:absolute`의 `left∙top`을 변경합니다. 3. `mouseup`에서는 드래그 앤 드롭 완료와 관련된 모든 작업을 수행합니다. -<<<<<<< HEAD 여기까지가 기본 알고리즘입니다. 이후에는 이동 중인 요소 아래에 있는 다른 요소를 강조하는 기능을 알아보겠습니다. -======= -These are the basics. Later we'll see how to add other features, such as highlighting current underlying elements while we drag over them. ->>>>>>> upstream/master 공을 드래그하는 구현 방법은 다음과 같습니다. ```js -<<<<<<< HEAD ball.onmousedown = function(event) { // (1) absolute 속성과 zIndex 프로퍼티를 수정해 공이 제일 위에서 움직이기 위한 준비를 합니다. ball.style.position = 'absolute'; @@ -36,16 +31,6 @@ ball.onmousedown = function(event) { // 현재 위치한 부모에서 body로 직접 이동하여 // body를 기준으로 위치를 지정합니다. document.body.append(ball); -======= -ball.onmousedown = function(event) { - // (1) prepare to moving: make absolute and on top by z-index - ball.style.position = 'absolute'; - ball.style.zIndex = 1000; - - // move it out of any current parents directly into body - // to make it positioned relative to the body - document.body.append(ball); ->>>>>>> upstream/master // 공을 pageX, pageY 좌표 중앙에 위치하게 합니다. function moveAt(pageX, pageY) { @@ -108,22 +93,14 @@ document의 중간이나 윈도우 어딘가로 점프 되는 현상을 잡기 ## 올바른 위치 지정 -<<<<<<< HEAD 위 예제 코드에서 공은 항상 포인터 아래로 이동합니다. -======= -In the examples above the ball is always moved so that its center is under the pointer: ->>>>>>> upstream/master ```js ball.style.left = pageX - ball.offsetWidth / 2 + 'px'; ball.style.top = pageY - ball.offsetHeight / 2 + 'px'; ``` -<<<<<<< HEAD 나쁘진 않습니다. 다만, 몇 가지 부작용이 있습니다. 드래그 앤 드롭을 시작하기 위해 공 위 어디에서든 `mousedown`을 할 수 있습니다. 공의 가장자리에서 `mousedown`을 하게 되면, 마우스 포인터 아래로 공이 갑자기 점프 되는 부작용이 발생합니다. -======= -Not bad, but there's a side effect. To initiate the drag'n'drop, we can `mousedown` anywhere on the ball. But if "take" it from its edge, then the ball suddenly "jumps" to become centered under the mouse pointer. ->>>>>>> upstream/master 포인터를 기준으로 요소의 초기 이동을 유지하는 방법이 포인터 중앙으로 요소를 이동시키는 방법보다 더 좋습니다. @@ -147,11 +124,7 @@ Not bad, but there's a side effect. To initiate the drag'n'drop, we can `mousedo ```js // onmousemove -<<<<<<< HEAD // 공은 고정된 포지션을 갖습니다. -======= - // ball has position:absolute ->>>>>>> upstream/master ball.style.left = event.pageX - *!*shiftX*/!* + 'px'; ball.style.top = event.pageY - *!*shiftY*/!* + 'px'; ``` @@ -246,11 +219,7 @@ ball.ondragstart = function() { 그러면 무엇을 해야 할까요? -<<<<<<< HEAD `document.elementFromPoint(clientX, clientY)`라는 메서드가 있습니다. 주어진 윈도우 기준 좌표에서 가장 많이 중첩된 요소를 반환합니다. (윈도우 밖의 좌표는 null) -======= -There's a method called `document.elementFromPoint(clientX, clientY)`. It returns the most nested element on given window-relative coordinates (or `null` if given coordinates are out of the window). If there are multiple overlapping elements on the same coordinates, then the topmost one is returned. ->>>>>>> upstream/master 다음과 같이 마우스 이벤트 핸들러에서 포인터 아래에 드롭 가능성을 감지할 수 있습니다. @@ -307,11 +276,7 @@ function onMouseMove(event) { } ``` -<<<<<<< HEAD 아래 예시에서 공을 축구 골대 위로 드래그하면 골대가 강조 표시됩니다. -======= -In the example below when the ball is dragged over the soccer goal, the goal is highlighted. ->>>>>>> upstream/master [codetabs height=250 src="ball4"] @@ -335,8 +300,4 @@ In the example below when the ball is dragged over the soccer goal, the goal is - `mousedown/up`에 이벤트 위임을 사용할 수 있습니다. `event.target`을 확인하는 넓은 영역의 이벤트 핸들러는 수백 개의 요소에 대한 드래그 앤 드롭을 관리할 수 있습니다. - 등등 -<<<<<<< HEAD `DragZone`, `Droppable`, `Draggable` 및 기타 클래스 등 아키텍처를 구축하는 프레임워크가 있습니다. 대부분은 앞서 드래그와 드롭에 대한 설명과 유사한 작업을 하므로 이해하기 쉽습니다. 때로는 제3의 솔루션 적용보다 쉽게 수행할 수 있습니다. -======= -There are frameworks that build architecture over it: `DragZone`, `Droppable`, `Draggable` and other classes. Most of them do the similar stuff to what's described above, so it should be easy to understand them now. Or roll your own, as you can see that that's easy enough to do, sometimes easier than adapting a third-party solution. ->>>>>>> upstream/master diff --git a/2-ui/3-event-details/6-pointer-events/article.md b/2-ui/3-event-details/6-pointer-events/article.md index 557f7b31a5..174e0fe095 100644 --- a/2-ui/3-event-details/6-pointer-events/article.md +++ b/2-ui/3-event-details/6-pointer-events/article.md @@ -1,44 +1,36 @@ -# Pointer events +# 포인터 이벤트 -Pointer events are a modern way to handle input from a variety of pointing devices, such as a mouse, a pen/stylus, a touchscreen, and so on. +포인터 이벤트(Pointer events)는 마우스, 펜·스타일러스, 터치스크린 같은 다양한 포인팅 기기의 입력을 처리하는 현대적인 방법입니다. -## The brief history +## 간략한 역사 -Let's make a small overview, so that you understand the general picture and the place of Pointer Events among other event types. +포인터 이벤트가 다른 이벤트 유형 사이에서 어떤 위치에 있는지 전체 그림을 이해할 수 있도록 간략히 살펴보겠습니다. -- Long ago, in the past, there were only mouse events. +- 오래전에는 마우스 이벤트만 있었습니다. - Then touch devices became widespread, phones and tablets in particular. For the existing scripts to work, they generated (and still generate) mouse events. For instance, tapping a touchscreen generates `mousedown`. So touch devices worked well with web pages. -<<<<<<< HEAD - -======= + 그러다 터치 기기, 특히 휴대 전화와 태블릿이 널리 보급되었습니다. 기존 스크립트가 동작하도록 터치 기기는 마우스 이벤트를 생성했고 지금도 생성합니다. 예를 들어 터치스크린을 탭 하면 `mousedown`이 발생합니다. 덕분에 터치 기기는 웹 페이지와 잘 동작했습니다. ->>>>>>> upstream/master - But touch devices have more capabilities than a mouse. For example, it's possible to touch multiple points at once ("multi-touch"). Although, mouse events don't have necessary properties to handle such multi-touches. + 하지만 터치 기기는 마우스보다 더 많은 기능을 제공합니다. 예를 들어 여러 지점을 동시에 터치하는 '멀티 터치'가 가능합니다. 하지만 마우스 이벤트에는 이런 멀티 터치를 처리하는 데 필요한 프로퍼티가 없습니다. -- So touch events were introduced, such as `touchstart`, `touchend`, `touchmove`, that have touch-specific properties (we don't cover them in detail here, because pointer events are even better). +- 그래서 `touchstart`, `touchend`, `touchmove`처럼 터치에 특화된 프로퍼티를 가진 터치 이벤트가 도입되었습니다. 포인터 이벤트가 더 나은 방식이므로 여기서는 자세히 다루지 않겠습니다. - Still, it wasn't enough, as there are many other devices, such as pens, that have their own features. Also, writing code that listens for both touch and mouse events was cumbersome. + 하지만 그것만으로는 부족했습니다. 펜처럼 저마다 고유 기능을 가진 다른 기기도 많았기 때문입니다. 터치 이벤트와 마우스 이벤트를 모두 수신하는 코드를 작성하는 일도 번거로웠습니다. -- To solve these issues, the new standard Pointer Events was introduced. It provides a single set of events for all kinds of pointing devices. +- 이런 문제를 해결하기 위해 새로운 표준인 포인터 이벤트가 도입되었습니다. 포인터 이벤트는 모든 종류의 포인팅 기기에 대해 하나의 이벤트 집합을 제공합니다. -<<<<<<< HEAD -As of now, [Pointer Events Level 2](https://www.w3.org/TR/pointerevents2/) specification is supported in all major browsers, while the newer [Pointer Events Level 3](https://w3c.github.io/pointerevents/) is in the works and is mostly compartible with Pointer Events level 2. -======= -As of now, [Pointer Events Level 2](https://www.w3.org/TR/pointerevents2/) specification is supported in all major browsers, while the newer [Pointer Events Level 3](https://w3c.github.io/pointerevents/) is in the works and is mostly compatible with Pointer Events level 2. ->>>>>>> upstream/master +현재 [Pointer Events Level 2](https://www.w3.org/TR/pointerevents2/) 명세는 모든 주요 브라우저에서 지원됩니다. 더 최신 버전인 [Pointer Events Level 3](https://w3c.github.io/pointerevents/)는 작업 중이며 Pointer Events Level 2와 대부분 호환됩니다. -Unless you develop for old browsers, such as Internet Explorer 10, or for Safari 12 or below, there's no point in using mouse or touch events any more -- we can switch to pointer events. +Internet Explorer 10이나 Safari 12 이하 같은 구형 브라우저를 지원해야 하는 경우가 아니라면, 이제 마우스 이벤트나 터치 이벤트를 사용할 이유가 없습니다. 포인터 이벤트로 전환하면 됩니다. -Then your code will work well with both touch and mouse devices. +그러면 터치 기기와 마우스 기기 모두에서 코드가 잘 동작합니다. -That said, there are some important peculiarities that one should know in order to use Pointer Events correctly and avoid surprises. We'll make note of them in this article. +다만 포인터 이벤트를 올바르게 사용하고 예상치 못한 동작을 피하려면 알아두어야 할 중요한 특징이 몇 가지 있습니다. 이 챕터에서 그 특징을 짚어보겠습니다. -## Pointer event types +## 포인터 이벤트 종류 -Pointer events are named similarly to mouse events: +포인터 이벤트의 이름은 마우스 이벤트와 유사하게 지어졌습니다. -| Pointer event | Similar mouse event | +| 포인터 이벤트 | 유사한 마우스 이벤트 | |---------------|-------------| | `pointerdown` | `mousedown` | | `pointerup` | `mouseup` | @@ -51,201 +43,142 @@ Pointer events are named similarly to mouse events: | `gotpointercapture` | - | | `lostpointercapture` | - | -As we can see, for every `mouse`, there's a `pointer` that plays a similar role. Also there are 3 additional pointer events that don't have a corresponding `mouse...` counterpart, we'll explain them soon. +표에서 볼 수 있듯이 모든 `mouse`에는 비슷한 역할을 하는 `pointer`가 대응됩니다. 여기에 대응하는 `mouse...` 이벤트가 없는 포인터 이벤트도 세 가지 있는데, 곧 설명하겠습니다. -```smart header="Replacing `mouse` with `pointer` in our code" -We can replace `mouse` events with `pointer` in our code and expect things to continue working fine with mouse. +```smart header="코드에서 `mouse`를 `pointer`로 바꾸기" +코드에서 `mouse` 이벤트를 `pointer`로 바꿔도 마우스에서 계속 잘 동작합니다. -<<<<<<< HEAD -The support for touch devices will also "magically" improve. Although, we may need to add `touch-action: none` in some places in CSS. We'll cover it below in the section about `pointercancel`. -======= -The support for touch devices will also "magically" improve. Although, we may need to add `touch-action: none` in some places in CSS. We'll cover it below in the section about `pointercancel`. ->>>>>>> upstream/master +터치 기기 지원도 '마법처럼' 좋아집니다. 다만 CSS에서 몇 군데에 `touch-action: none`을 추가해야 할 수도 있습니다. 아래 `pointercancel`에서 다루겠습니다. ``` -## Pointer event properties +## 포인터 이벤트 프로퍼티 -Pointer events have the same properties as mouse events, such as `clientX/Y`, `target`, etc., plus some others: +포인터 이벤트는 `clientX·clientY`, `target` 등 마우스 이벤트와 동일한 프로퍼티를 가지며, 여기에 몇 가지 프로퍼티가 더 있습니다. -- `pointerId` - the unique identifier of the pointer causing the event. -<<<<<<< HEAD - - Browser-generated. Allows us to handle multiple pointers, such as a touchscreen with stylus and multi-touch (examples will follow). -- `pointerType` - the pointing device type. Must be a string, one of: "mouse", "pen" or "touch". -======= +- `pointerId` - 이벤트를 일으킨 포인터의 고유 식별자입니다. - Browser-generated. Allows us to handle multiple pointers, such as a touchscreen with stylus and multi-touch (examples will follow). -- `pointerType` - the pointing device type. Must be a string, one of: "mouse", "pen" or "touch". ->>>>>>> upstream/master + 브라우저가 생성합니다. 스타일러스와 멀티 터치를 지원하는 터치스크린처럼 여러 포인터를 처리할 수 있게 해줍니다. 예시는 뒤에서 살펴보겠습니다. +- `pointerType` - 포인팅 기기의 유형입니다. "mouse", "pen", "touch" 중 하나인 문자열이어야 합니다. - We can use this property to react differently on various pointer types. -- `isPrimary` - is `true` for the primary pointer (the first finger in multi-touch). + 이 프로퍼티를 사용하면 포인터 유형에 따라 다르게 반응할 수 있습니다. +- `isPrimary` - 주 포인터, 즉 멀티 터치에서 첫 번째 손가락이면 `true`입니다. -Some pointer devices measure contact area and pressure, e.g. for a finger on the touchscreen, there are additional properties for that: +일부 포인터 기기는 접촉 면적과 압력을 측정합니다. 예를 들어 터치스크린에 닿은 손가락에 대해 다음과 같은 추가 프로퍼티가 있습니다. -<<<<<<< HEAD -- `width` - the width of the area where the pointer (e.g. a finger) touches the device. Where unsupported, e.g. for a mouse, it's always `1`. -======= -- `width` - the width of the area where the pointer (e.g. a finger) touches the device. Where unsupported, e.g. for a mouse, it's always `1`. ->>>>>>> upstream/master -- `height` - the height of the area where the pointer touches the device. Where unsupported, it's always `1`. -- `pressure` - the pressure of the pointer tip, in range from 0 to 1. For devices that don't support pressure must be either `0.5` (pressed) or `0`. -- `tangentialPressure` - the normalized tangential pressure. -- `tiltX`, `tiltY`, `twist` - pen-specific properties that describe how the pen is positioned relative to the surface. +- `width` - 포인터, 예를 들어 손가락이 기기에 닿은 영역의 너비입니다. 마우스처럼 지원되지 않을 때는 항상 `1`입니다. +- `height` - 포인터가 기기에 닿은 영역의 높이입니다. 지원되지 않을 때는 항상 `1`입니다. +- `pressure` - 포인터 끝의 압력으로, 범위는 0부터 1까지입니다. 압력을 지원하지 않는 기기에서는 `0.5`(눌림) 또는 `0`이어야 합니다. +- `tangentialPressure` - 정규화된 접선 방향 압력입니다. +- `tiltX`, `tiltY`, `twist` - 펜이 표면을 기준으로 어떻게 놓였는지 설명하는 펜 전용 프로퍼티입니다. -These properties aren't supported by most devices, so they are rarely used. You can find the details about them in the [specification](https://w3c.github.io/pointerevents/#pointerevent-interface) if needed. +이 프로퍼티들은 대부분의 기기에서 지원되지 않아 잘 사용되지 않습니다. 필요하다면 [명세](https://w3c.github.io/pointerevents/#pointerevent-interface)에서 자세한 내용을 확인할 수 있습니다. -## Multi-touch +## 멀티 터치 -One of the things that mouse events totally don't support is multi-touch: a user can touch in several places at once on their phone or tablet, or perform special gestures. +마우스 이벤트가 전혀 지원하지 않는 기능 중 하나가 멀티 터치입니다. 사용자는 휴대 전화나 태블릿에서 여러 곳을 동시에 터치하거나 특수 제스처를 수행할 수 있습니다. -Pointer Events allow handling multi-touch with the help of the `pointerId` and `isPrimary` properties. +포인터 이벤트는 `pointerId`와 `isPrimary` 프로퍼티를 활용해 멀티 터치를 처리할 수 있습니다. -Here's what happens when a user touches a touchscreen in one place, then puts another finger somewhere else on it: +사용자가 터치스크린의 한 곳을 터치한 다음 다른 손가락을 다른 곳에 올리면 다음과 같은 일이 발생합니다. -1. At the first finger touch: - - `pointerdown` with `isPrimary=true` and some `pointerId`. -2. For the second finger and more fingers (assuming the first one is still touching): - - `pointerdown` with `isPrimary=false` and a different `pointerId` for every finger. +1. 첫 번째 손가락이 터치될 때 + - `isPrimary=true`와 어떤 `pointerId`를 가진 `pointerdown`이 발생합니다. +2. 첫 번째 손가락이 아직 닿아 있다고 가정하고 두 번째 손가락과 그 이후의 손가락이 터치된 경우 + - 손가락마다 `isPrimary=false`와 서로 다른 `pointerId`를 가진 `pointerdown`이 발생합니다. -Please note: the `pointerId` is assigned not to the whole device, but for each touching finger. If we use 5 fingers to simultaneously touch the screen, we have 5 `pointerdown` events, each with their respective coordinates and a different `pointerId`. +주의할 점은 `pointerId`가 기기 전체가 아니라 터치 중인 각 손가락에 할당된다는 것입니다. 손가락 5개로 화면을 동시에 터치하면 `pointerdown` 이벤트가 5개 발생하고, 각 이벤트는 저마다의 좌표와 서로 다른 `pointerId`를 가집니다. -The events associated with the first finger always have `isPrimary=true`. +첫 번째 손가락과 관련된 이벤트는 항상 `isPrimary=true`를 가집니다. -We can track multiple touching fingers using their `pointerId`. When the user moves and then removes a finger, we get `pointermove` and `pointerup` events with the same `pointerId` as we had in `pointerdown`. +`pointerId`를 사용하면 여러 손가락의 터치를 추적할 수 있습니다. 사용자가 손가락을 움직인 다음 떼면, `pointerdown`에서 받았던 것과 같은 `pointerId`를 가진 `pointermove`와 `pointerup` 이벤트가 발생합니다. ```online -Here's the demo that logs `pointerdown` and `pointerup` events: +`pointerdown`과 `pointerup` 이벤트를 기록하는 데모입니다. [iframe src="multitouch" edit height=200] -Please note: you must be using a touchscreen device, such as a phone or a tablet, to actually see the difference in `pointerId/isPrimary`. For single-touch devices, such as a mouse, there'll be always same `pointerId` with `isPrimary=true`, for all pointer events. +참고로 `pointerId·isPrimary`의 차이를 실제로 확인하려면 휴대 전화나 태블릿 같은 터치스크린 기기를 사용해야 합니다. 마우스 같은 단일 터치 기기에서는 모든 포인터 이벤트에서 항상 같은 `pointerId`와 `isPrimary=true`가 사용됩니다. ``` -## Event: pointercancel +## pointercancel 이벤트 -<<<<<<< HEAD -The `pointercancel` event fires when there's an ongoing pointer interaction, and then something happens that causes it to be aborted, so that no more pointer events are generated. +`pointercancel` 이벤트는 포인터 상호작용이 진행 중일 때, 그 상호작용을 중단시키는 일이 발생해 더 이상 포인터 이벤트가 생성되지 않을 때 발생합니다. -Such causes are: -- The pointer device hardware was physically disabled. -- The device orientation changed (tablet rotated). -======= -The `pointercancel` event fires when there's an ongoing pointer interaction, and then something happens that causes it to be aborted, so that no more pointer events are generated. +원인은 다음과 같습니다. +- 포인터 기기 하드웨어가 물리적으로 비활성화된 경우 +- 기기 방향이 바뀐 경우(태블릿 회전) +- 브라우저가 상호작용을 마우스 제스처나 확대·이동 동작 등으로 보고 직접 처리하기로 한 경우 -Such causes are: -- The pointer device hardware was physically disabled. -- The device orientation changed (tablet rotated). ->>>>>>> upstream/master -- The browser decided to handle the interaction on its own, considering it a mouse gesture or zoom-and-pan action or something else. +`pointercancel`이 어떤 영향을 주는지 실제 예시로 확인해 보겠습니다. -We'll demonstrate `pointercancel` on a practical example to see how it affects us. + 글의 초반부처럼 공을 드래그 앤 드롭하는 기능을 구현한다고 가정해 봅시다. -Let's say we're implementing drag'n'drop for a ball, just as in the beginning of the article . +사용자 동작의 흐름과 그에 대응하는 이벤트는 다음과 같습니다. -Here is the flow of user actions and the corresponding events: +1) 사용자가 이미지를 눌러 드래그를 시작합니다. + - `pointerdown` 이벤트가 발생합니다. +2) 그런 다음 포인터를 움직이기 시작합니다. 따라서 이미지가 드래그됩니다. + - `pointermove`가 발생합니다. 여러 번 발생할 수도 있습니다. +3) 그런데 여기서 예상치 못한 일이 벌어집니다! 브라우저에는 이미지를 위한 기본 드래그 앤 드롭 지원이 있는데, 이 기능이 드래그 앤 드롭 과정을 가로채면서 `pointercancel` 이벤트를 발생시킵니다. + - 이제 브라우저가 이미지의 드래그 앤 드롭을 직접 처리합니다. 사용자는 공 이미지를 브라우저 밖으로 끌어내 메일 프로그램이나 파일 관리자에 놓을 수도 있습니다. + - 더 이상 `pointermove` 이벤트는 발생하지 않습니다. -1) The user presses on an image, to start dragging - - `pointerdown` event fires -2) Then they start moving the pointer (thus dragging the image) - - `pointermove` fires, maybe several times -3) And then the surprise happens! The browser has native drag'n'drop support for images, that kicks in and takes over the drag'n'drop process, thus generating `pointercancel` event. - - The browser now handles drag'n'drop of the image on its own. The user may even drag the ball image out of the browser, into their Mail program or a File Manager. - - No more `pointermove` events for us. - -So the issue is that the browser "hijacks" the interaction: `pointercancel` fires in the beginning of the "drag-and-drop" process, and no more `pointermove` events are generated. +따라서 문제는 브라우저가 상호작용을 '가로챈다'라는 데 있습니다. '드래그 앤 드롭' 과정이 시작될 때 `pointercancel`이 발생하고, 이후에는 `pointermove` 이벤트가 더 이상 생성되지 않습니다. ```online -<<<<<<< HEAD -Here's the drag'n'drop demo with loggin of pointer events (only `up/down`, `move` and `cancel`) in the `textarea`: -======= -Here's the drag'n'drop demo with logging of pointer events (only `up/down`, `move` and `cancel`) in the `textarea`: ->>>>>>> upstream/master +`textarea`에 포인터 이벤트(`up·down`, `move`, `cancel`만)를 기록하는 드래그 앤 드롭 데모입니다. [iframe src="ball" height=240 edit] ``` -We'd like to implement the drag'n'drop on our own, so let's tell the browser not to take it over. +직접 드래그 앤 드롭을 구현하려면 브라우저가 이를 가로채지 않도록 해야 합니다. -**Prevent the default browser action to avoid `pointercancel`.** +**`pointercancel`을 방지하려면 브라우저 기본 동작을 막으세요.** -We need to do two things: +두 가지 작업이 필요합니다. -1. Prevent native drag'n'drop from happening: - - We can do this by setting `ball.ondragstart = () => false`, just as described in the article . - - That works well for mouse events. -2. For touch devices, there are other touch-related browser actions (besides drag'n'drop). To avoid problems with them too: -<<<<<<< HEAD - - Prevent them by setting `#ball { touch-action: none }` in CSS. -======= - - Prevent them by setting `#ball { touch-action: none }` in CSS. ->>>>>>> upstream/master - - Then our code will start working on touch devices. +1. 기본 드래그 앤 드롭이 발생하지 않도록 막습니다. + - 에서 설명한 것처럼 `ball.ondragstart = () => false`를 설정하면 됩니다. + - 마우스 이벤트에서는 이 방법이 잘 동작합니다. +2. 터치 기기에는 드래그 앤 드롭 외에도 터치와 관련된 다른 브라우저 동작이 있습니다. 이 동작 때문에 생기는 문제도 피하려면 다음과 같이 합니다. + - CSS에서 `#ball { touch-action: none }`을 설정해 막습니다. + - 그러면 코드가 터치 기기에서도 작동하기 시작합니다. -After we do that, the events will work as intended, the browser won't hijack the process and doesn't emit `pointercancel`. +이렇게 하면 이벤트가 의도대로 동작하고, 브라우저가 과정을 가로채거나 `pointercancel`을 발생시키지 않습니다. ```online -This demo adds these lines: +이 데모는 위 코드를 추가한 버전입니다. [iframe src="ball-2" height=240 edit] -As you can see, there's no `pointercancel` any more. +확인할 수 있듯이 더 이상 `pointercancel`은 발생하지 않습니다. ``` -Now we can add the code to actually move the ball, and our drag'n'drop will work for mouse devices and touch devices. - -## Pointer capturing - -Pointer capturing is a special feature of pointer events. - -The idea is very simple, but may seem quite odd at first, as nothing like that exists for any other event type. - -The main method is: -<<<<<<< HEAD -- `elem.setPointerCapture(pointerId)` - binds events with the given `pointerId` to `elem`. After the call all pointer events with the same `pointerId` will have `elem` as the target (as if happened on `elem`), no matter where in document they really happened. -======= -- `elem.setPointerCapture(pointerId)` -- binds events with the given `pointerId` to `elem`. After the call all pointer events with the same `pointerId` will have `elem` as the target (as if happened on `elem`), no matter where in document they really happened. ->>>>>>> upstream/master - -In other words, `elem.setPointerCapture(pointerId)` retargets all subsequent events with the given `pointerId` to `elem`. - -The binding is removed: -- automatically when `pointerup` or `pointercancel` events occur, -- automatically when `elem` is removed from the document, -- when `elem.releasePointerCapture(pointerId)` is called. +이제 실제로 공을 움직이는 코드를 추가할 수 있고, 드래그 앤 드롭이 마우스 기기와 터치 기기에서 모두 동작합니다. -<<<<<<< HEAD -**Pointer capturing can be used to simplify drag'n'drop kind of interactions.** +## 포인터 캡처링 -As an example, let's recall how one can implement a custom slider, described in the . +포인터 캡처링(Pointer capturing)은 포인터 이벤트의 특별한 기능입니다. -We make a slider element with the strip and the "runner" (`thumb`) inside it. +개념은 매우 단순하지만, 다른 이벤트 유형에는 이런 기능이 없어 처음에는 꽤 낯설어 보일 수 있습니다. -Then it works like this: +주요 메서드는 다음과 같습니다. +- `elem.setPointerCapture(pointerId)` -- 지정한 `pointerId`를 가진 이벤트를 `elem`에 바인딩합니다. 호출 이후에는 같은 `pointerId`를 가진 모든 포인터 이벤트가 실제로 문서 어디에서 발생했든 상관없이 `elem`을 타깃으로 갖습니다. 마치 `elem`에서 발생한 것처럼 처리됩니다. -1. The user presses on the slider `thumb` - `pointerdown` triggers. -2. Then they move the pointer - `pointermove` triggers, and we move the `thumb` along. - - ...As the pointer moves, it may leave the slider `thumb`: go above or below it. The `thumb` should move strictly horizontally, remaining aligned with the pointer. +다시 말해 `elem.setPointerCapture(pointerId)`는 이후에 발생하는, 지정한 `pointerId`를 가진 모든 이벤트의 타깃을 `elem`으로 재지정합니다. -So, to track all pointer movements, including when it goes above/below the `thumb`, we had to assign `pointermove` event handler on the whole `document`. +바인딩은 다음과 같은 경우에 해제됩니다. +- `pointerup` 또는 `pointercancel` 이벤트가 발생하면 자동으로 해제됩니다. +- `elem`이 문서에서 제거되면 자동으로 해제됩니다. +- `elem.releasePointerCapture(pointerId)`가 호출되면 해제됩니다. -That solution looks a bit "dirty". One of the problems is that pointer movements around the document may cause side effects, trigger other event handlers, totally not related to the slider. +그렇다면 어디에 유용할까요? 실제 예시를 볼 차례입니다. -Pointer capturing provides a means to bind `pointermove` to `thumb` and avoid any such problems: +**포인터 캡처링은 드래그 앤 드롭 같은 상호작용을 단순화하는 데 사용할 수 있습니다.** -- We can call `thumb.setPointerCapture(event.pointerId)` in `pointerdown` handler, -- Then future pointer events until `pointerup/cancel` will be retargeted to `thumb`. -- When `pointerup` happens (dragging complete), the binding is removed automatically, we don't need to care about it. +에서 설명한 커스텀 슬라이더 구현 방법을 떠올려 봅시다. -So, even if the user moves the pointer around the whole document, events handlers will be called on `thumb`. Besides, coordinate properties of the event objects, such as `clientX/clientY` will still be correct - the capturing only affects `target/currentTarget`. -======= -Now what is it good for? It's time to see a real-life example. - -**Pointer capturing can be used to simplify drag'n'drop kind of interactions.** - -Let's recall how one can implement a custom slider, described in the . - -We can make a `slider` element to represent the strip and the "runner" (`thumb`) inside it: +막대를 나타내는 `slider` 요소와 그 안의 '러너'(`thumb`)를 만들 수 있습니다. ```html
@@ -253,120 +186,97 @@ We can make a `slider` element to represent the strip and the "runner" (`thumb`)
``` -With styles, it looks like this: +스타일을 적용하면 다음과 같습니다. [iframe src="slider-html" height=40 edit]

-And here's the working logic, as it was described, after replacing mouse events with similar pointer events: +마우스 이벤트를 유사한 포인터 이벤트로 바꾼 뒤의 동작 로직은 다음과 같습니다. -1. The user presses on the slider `thumb` -- `pointerdown` triggers. -2. Then they move the pointer -- `pointermove` triggers, and our code moves the `thumb` element along. - - ...As the pointer moves, it may leave the slider `thumb` element, go above or below it. The `thumb` should move strictly horizontally, remaining aligned with the pointer. +1. 사용자가 슬라이더 `thumb`를 누르면 `pointerdown`이 발생합니다. +2. 그런 다음 포인터를 움직이면 `pointermove`가 발생하고, 코드가 `thumb` 요소를 함께 움직입니다. + - ...포인터가 움직이다 보면 슬라이더 `thumb` 요소를 벗어나 위아래로 이동할 수 있습니다. 그래도 `thumb`는 포인터에 맞춰 정확히 수평 방향으로만 이동해야 합니다. -In the mouse event based solution, to track all pointer movements, including when it goes above/below the `thumb`, we had to assign `mousemove` event handler on the whole `document`. +마우스 이벤트 기반 해결책에서는 포인터가 `thumb` 위아래로 이동하는 경우까지 포함해 모든 포인터 움직임을 추적하려고 전체 `document`에 `mousemove` 이벤트 핸들러를 할당해야 했습니다. -That's not a cleanest solution, though. One of the problems is that when a user moves the pointer around the document, it may trigger event handlers (such as `mouseover`) on some other elements, invoke totally unrelated UI functionality, and we don't want that. +하지만 그다지 깔끔한 해결책은 아닙니다. 문제 중 하나는 사용자가 문서 여기저기로 포인터를 움직일 때 다른 요소의 이벤트 핸들러, 예를 들어 `mouseover`를 트리거 해 전혀 관련 없는 UI 기능을 실행할 수 있다는 점입니다. 이는 원하지 않는 동작입니다. -This is the place where `setPointerCapture` comes into play. +이럴 때 `setPointerCapture`가 등장합니다. -- We can call `thumb.setPointerCapture(event.pointerId)` in `pointerdown` handler, -- Then future pointer events until `pointerup/cancel` will be retargeted to `thumb`. -- When `pointerup` happens (dragging complete), the binding is removed automatically, we don't need to care about it. +- `pointerdown` 핸들러에서 `thumb.setPointerCapture(event.pointerId)`를 호출합니다. +- 이후 `pointerup·pointercancel`까지의 포인터 이벤트는 `thumb`로 재지정됩니다. +- `pointerup`이 발생하면, 즉 드래그가 완료되면 바인딩은 자동으로 해제되므로 신경 쓸 필요가 없습니다. -So, even if the user moves the pointer around the whole document, events handlers will be called on `thumb`. Nevertheless, coordinate properties of the event objects, such as `clientX/clientY` will still be correct - the capturing only affects `target/currentTarget`. ->>>>>>> upstream/master +따라서 사용자가 문서 전체에서 포인터를 움직이더라도 이벤트 핸들러는 `thumb`에서 호출됩니다. 그럼에도 `clientX·clientY` 같은 이벤트 객체의 좌표 프로퍼티는 여전히 올바릅니다. 캡처링은 `target·currentTarget`에만 영향을 줍니다. -Here's the essential code: +핵심 코드는 다음과 같습니다. ```js thumb.onpointerdown = function(event) { - // retarget all pointer events (until pointerup) to thumb + // 모든 포인터 이벤트(pointerup까지)를 thumb으로 재지정합니다. thumb.setPointerCapture(event.pointerId); - // start tracking pointer moves + // 포인터 이동 추적을 시작합니다. thumb.onpointermove = function(event) { - // moving the slider: listen on the thumb, as all pointer events are retargeted to it + // 슬라이더 이동: 모든 포인터 이벤트가 thumb으로 재지정되므로 thumb에서 처리합니다. let newLeft = event.clientX - slider.getBoundingClientRect().left; thumb.style.left = newLeft + 'px'; }; - // on pointer up finish tracking pointer moves + // pointerup에서 포인터 이동 추적을 끝냅니다. thumb.onpointerup = function(event) { thumb.onpointermove = null; thumb.onpointerup = null; - // ...also process the "drag end" if needed + // ...필요하다면 "드래그 종료"도 처리합니다. }; }; -<<<<<<< HEAD -thumb.onpointermove = function(event) { - // moving the slider: listen on the thumb, as all pointer events are retargeted to it - let newLeft = event.clientX - slider.getBoundingClientRect().left; - thumb.style.left = newLeft + 'px'; -}; - -// note: no need to call thumb.releasePointerCapture, -======= -// note: no need to call thumb.releasePointerCapture, ->>>>>>> upstream/master -// it happens on pointerup automatically +// thumb.releasePointerCapture를 호출할 필요는 없습니다. +// pointerup에서 자동으로 처리됩니다. ``` ```online -The full demo: +전체 데모입니다. [iframe src="slider" height=100 edit]

-In the demo, there's also an additional element with `onmouseover` handler showing the current date. +데모에는 현재 날짜를 보여주는 `onmouseover` 핸들러가 있는 추가 요소도 있습니다. -Please note: while you're dragging the thumb, you may hover over this element, and its handler *does not* trigger. +thumb을 드래그하는 동안 이 요소 위로 마우스를 올려도 핸들러가 *실행되지 않는다*는 점에 주목하세요. -So the dragging is now free of side effects, thanks to `setPointerCapture`. +`setPointerCapture` 덕분에 이제 드래그에 부작용이 없습니다. ``` -<<<<<<< HEAD -At the end, pointer capturing gives us two benefits: -1. The code becomes cleaner as we don't need to add/remove handlers on the whole `document` any more. The binding is released automatically. -2. If there are any `pointermove` handlers in the document, they won't be accidentally triggered by the pointer while the user is dragging the slider. - -### Pointer capturing events -======= ->>>>>>> upstream/master -At the end, pointer capturing gives us two benefits: -1. The code becomes cleaner as we don't need to add/remove handlers on the whole `document` any more. The binding is released automatically. -2. If there are other pointer event handlers in the document, they won't be accidentally triggered by the pointer while the user is dragging the slider. +결국 포인터 캡처링은 두 가지 이점을 줍니다. +1. 전체 `document`에 핸들러를 추가하거나 제거할 필요가 없어 코드가 더 깔끔해집니다. 바인딩은 자동으로 해제됩니다. +2. 문서에 다른 포인터 이벤트 핸들러가 있어도 사용자가 슬라이더를 드래그하는 동안 포인터 때문에 실수로 트리거 되지 않습니다. -### Pointer capturing events +### 포인터 캡처링 이벤트 -There's one more thing to mention here, for the sake of completeness. +완전성을 위해 한 가지 더 언급하겠습니다. -There are two events associated with pointer capturing: +포인터 캡처링과 관련된 이벤트는 두 가지입니다. -- `gotpointercapture` fires when an element uses `setPointerCapture` to enable capturing. -- `lostpointercapture` fires when the capture is released: either explicitly with `releasePointerCapture` call, or automatically on `pointerup`/`pointercancel`. +- `gotpointercapture`는 요소가 `setPointerCapture`를 사용해 캡처링을 활성화할 때 발생합니다. +- `lostpointercapture`는 캡처가 해제될 때 발생합니다. 해제는 releasePointerCapture를 직접 호출해서 이루어질 수도 있고, `pointerup`·`pointercancel` 시 자동으로 이루어질 수도 있습니다. -## Summary +## 요약 -Pointer events allow handling mouse, touch and pen events simultaneously, with a single piece of code. +포인터 이벤트를 사용하면 하나의 코드로 마우스, 터치, 펜 이벤트를 동시에 처리할 수 있습니다. -Pointer events extend mouse events. We can replace `mouse` with `pointer` in event names and expect our code to continue working for mouse, with better support for other device types. +포인터 이벤트는 마우스 이벤트를 확장합니다. 이벤트 이름에서 `mouse`를 `pointer`로 바꾸어도 마우스에서 계속 동작하며, 다른 기기 유형에 대한 지원도 향상됩니다. -<<<<<<< HEAD -For drag'n'drops and complex touch interactions that the browser may decide to hijack and handle on its own - remember to cancel the default action on events and set `touch-events: none` in CSS for elements that we engage. -======= -For drag'n'drops and complex touch interactions that the browser may decide to hijack and handle on its own - remember to cancel the default action on events and set `touch-action: none` in CSS for elements that we engage. ->>>>>>> upstream/master +브라우저가 가로채서 직접 처리할 수 있는 드래그 앤 드롭과 복잡한 터치 상호작용에서는, 이벤트의 기본 동작을 취소하고 관련 요소에 CSS로 `touch-action: none`을 설정해야 한다는 점을 잊지 마세요. -Additional abilities of pointer events are: +포인터 이벤트의 추가 기능은 다음과 같습니다. -- Multi-touch support using `pointerId` and `isPrimary`. -- Device-specific properties, such as `pressure`, `width/height`, and others. -- Pointer capturing: we can retarget all pointer events to a specific element until `pointerup`/`pointercancel`. +- `pointerId`와 `isPrimary`를 사용한 멀티 터치 지원 +- `pressure`, `width·height` 등 기기별 프로퍼티 +- 포인터 캡처링: `pointerup`·`pointercancel`까지 모든 포인터 이벤트를 특정 요소로 재지정할 수 있습니다. -As of now, pointer events are supported in all major browsers, so we can safely switch to them, especially if IE10- and Safari 12- are not needed. And even with those browsers, there are polyfills that enable the support of pointer events. +현재 포인터 이벤트는 모든 주요 브라우저에서 지원되므로, 특히 IE10 이하와 Safari 12 이하를 지원할 필요가 없다면 안전하게 전환할 수 있습니다. 해당 브라우저에서도 포인터 이벤트 지원을 가능하게 해주는 폴리필이 있습니다. \ No newline at end of file diff --git a/2-ui/3-event-details/7-keyboard-events/article.md b/2-ui/3-event-details/7-keyboard-events/article.md index 12fe632016..24965b8168 100644 --- a/2-ui/3-event-details/7-keyboard-events/article.md +++ b/2-ui/3-event-details/7-keyboard-events/article.md @@ -1,83 +1,83 @@ -# Keyboard: keydown and keyup +# keydown과 keyup -Before we get to keyboard, please note that on modern devices there are other ways to "input something". For instance, people use speech recognition (especially on mobile devices) or copy/paste with the mouse. +키보드를 다루기 전에 현대 기기에는 '무언가를 입력'하는 다른 방법도 있다는 점을 알아두세요. 예를 들어 음성 인식, 특히 모바일 기기에서의 음성 인식이나 마우스를 이용한 복사·붙여넣기가 있습니다. -So if we want to track any input into an `` field, then keyboard events are not enough. There's another event named `input` to track changes of an `` field, by any means. And it may be a better choice for such task. We'll cover it later in the chapter . +따라서 `` 필드에 들어오는 모든 입력을 추적하려면 키보드 이벤트만으로는 충분하지 않습니다. 어떤 방식으로든 `` 필드가 바뀌는 것을 추적하는 `input`이라는 이벤트가 따로 있습니다. 이런 작업에는 이 이벤트가 더 나은 선택일 수 있습니다. `input` 이벤트는 챕터에서 나중에 다루겠습니다. -Keyboard events should be used when we want to handle keyboard actions (virtual keyboard also counts). For instance, to react on arrow keys `key:Up` and `key:Down` or hotkeys (including combinations of keys). +키보드 이벤트는 가상 키보드를 포함한 키보드 동작을 처리하고 싶을 때 사용해야 합니다. 예를 들어 방향키 `key:Up`, `key:Down`에 반응하거나 단축키를 처리할 때 사용합니다. 키 조합도 여기에 포함됩니다. -## Teststand [#keyboard-test-stand] +## 테스트 환경 [#keyboard-test-stand] ```offline -To better understand keyboard events, you can use the [teststand](sandbox:keyboard-dump). +키보드 이벤트를 더 잘 이해하려면 [테스트 환경](sandbox:keyboard-dump)을 사용할 수 있습니다. ``` ```online -To better understand keyboard events, you can use the teststand below. +키보드 이벤트를 더 잘 이해하려면 아래 테스트 환경을 사용할 수 있습니다. -Try different key combinations in the text field. +텍스트 필드에서 여러 키 조합을 눌러 보세요. [codetabs src="keyboard-dump" height=480] ``` -## Keydown and keyup +## keydown과 keyup -The `keydown` events happens when a key is pressed down, and then `keyup` -- when it's released. +`keydown` 이벤트는 키를 누를 때 발생하고, `keyup` 이벤트는 키를 뗄 때 발생합니다. -### event.code and event.key +### event.code와 event.key -The `key` property of the event object allows to get the character, while the `code` property of the event object allows to get the "physical key code". +이벤트 객체의 `key` 프로퍼티로 문자를 얻을 수 있고, 이벤트 객체의 `code` 프로퍼티로 '물리적 키 코드'를 얻을 수 있습니다. -For instance, the same key `key:Z` can be pressed with or without `key:Shift`. That gives us two different characters: lowercase `z` and uppercase `Z`. +예를 들어 같은 `key:Z` 키도 `key:Shift`를 누르거나 누르지 않은 상태에서 누를 수 있습니다. 그러면 소문자 `z`와 대문자 `Z`라는 서로 다른 두 문자가 생깁니다. -The `event.key` is exactly the character, and it will be different. But `event.code` is the same: +`event.key`는 바로 그 문자이므로 달라집니다. 하지만 `event.code`는 같습니다. -| Key | `event.key` | `event.code` | +| 키 | `event.key` | `event.code` | |--------------|-------------|--------------| -| `key:Z` |`z` (lowercase) |`KeyZ` | -| `key:Shift+Z`|`Z` (uppercase) |`KeyZ` | +| `key:Z` |`z` (소문자) |`KeyZ` | +| `key:Shift+Z`|`Z` (대문자) |`KeyZ` | -If a user works with different languages, then switching to another language would make a totally different character instead of `"Z"`. That will become the value of `event.key`, while `event.code` is always the same: `"KeyZ"`. +사용자가 여러 언어를 사용한다면 다른 언어로 전환했을 때 `"Z"` 대신 완전히 다른 문자가 입력될 수 있습니다. 그 문자가 `event.key`의 값이 되지만, `event.code`는 항상 같습니다. `"KeyZ"`입니다. -```smart header="\"KeyZ\" and other key codes" -Every key has the code that depends on its location on the keyboard. Key codes described in the [UI Events code specification](https://www.w3.org/TR/uievents-code/). +```smart header="\"KeyZ\"와 기타 키 코드" +모든 키에는 키보드에서의 위치에 따라 정해지는 코드가 있습니다. 키 코드는 [UI Events code 명세](https://www.w3.org/TR/uievents-code/)에 설명되어 있습니다. -For instance: -- Letter keys have codes `"Key"`: `"KeyA"`, `"KeyB"` etc. -- Digit keys have codes: `"Digit"`: `"Digit0"`, `"Digit1"` etc. -- Special keys are coded by their names: `"Enter"`, `"Backspace"`, `"Tab"` etc. +예를 들면 다음과 같습니다. +- 문자 키에는 `"Key"` 형식의 코드가 있습니다. `"KeyA"`, `"KeyB"` 등입니다. +- 숫자 키에는 `"Digit"` 형식의 코드가 있습니다. `"Digit0"`, `"Digit1"` 등입니다. +- 특수 키는 이름으로 코드화됩니다. `"Enter"`, `"Backspace"`, `"Tab"` 등입니다. -There are several widespread keyboard layouts, and the specification gives key codes for each of them. +널리 쓰이는 키보드 레이아웃이 여러 가지 있으며, 명세는 각 레이아웃에 대한 키 코드를 제공합니다. -Read the [alphanumeric section of the spec](https://www.w3.org/TR/uievents-code/#key-alphanumeric-section) for more codes, or just press a key in the [teststand](#keyboard-test-stand) above. +더 많은 코드는 [명세의 영숫자 섹션](https://www.w3.org/TR/uievents-code/#key-alphanumeric-section)을 읽어보거나, 위 [테스트 환경](#keyboard-test-stand)에서 키를 눌러 확인할 수 있습니다. ``` -```warn header="Case matters: `\"KeyZ\"`, not `\"keyZ\"`" -Seems obvious, but people still make mistakes. +```warn header="대소문자는 중요합니다. `\"keyZ\"`가 아니라 `\"KeyZ\"`입니다" +당연해 보이지만 여전히 실수하는 경우가 있습니다. -Please evade mistypes: it's `KeyZ`, not `keyZ`. The check like `event.code=="keyZ"` won't work: the first letter of `"Key"` must be uppercase. +오타를 피해야 합니다. `keyZ`가 아니라 `KeyZ`입니다. `event.code=="keyZ"` 같은 검사는 동작하지 않습니다. `"Key"`의 첫 글자는 대문자여야 합니다. ``` -What if a key does not give any character? For instance, `key:Shift` or `key:F1` or others. For those keys, `event.key` is approximately the same as `event.code`: +문자를 만들어내지 않는 키라면 어떨까요? 예를 들어 `key:Shift`, `key:F1` 같은 키가 있습니다. 이런 키에서 `event.key`는 대체로 `event.code`와 같습니다. -| Key | `event.key` | `event.code` | +| 키 | `event.key` | `event.code` | |--------------|-------------|--------------| | `key:F1` |`F1` |`F1` | | `key:Backspace` |`Backspace` |`Backspace` | -| `key:Shift`|`Shift` |`ShiftRight` or `ShiftLeft` | +| `key:Shift`|`Shift` |`ShiftRight` 또는 `ShiftLeft` | -Please note that `event.code` specifies exactly which key is pressed. For instance, most keyboards have two `key:Shift` keys: on the left and on the right side. The `event.code` tells us exactly which one was pressed, and `event.key` is responsible for the "meaning" of the key: what it is (a "Shift"). +`event.code`는 어떤 키가 눌렸는지를 정확히 지정한다는 점에 유의해야 합니다. 예를 들어 대부분의 키보드에는 `key:Shift` 키가 왼쪽과 오른쪽에 두 개 있습니다. `event.code`는 정확히 어느 키가 눌렸는지 알려주고, `event.key`는 키의 '의미', 즉 그 키가 무엇인지(`"Shift"`)를 담당합니다. -Let's say, we want to handle a hotkey: `key:Ctrl+Z` (or `key:Cmd+Z` for Mac). Most text editors hook the "Undo" action on it. We can set a listener on `keydown` and check which key is pressed. +단축키 `key:Ctrl+Z`, Mac에서는 `key:Cmd+Z`를 처리하고 싶다고 가정해 봅시다. 대부분의 텍스트 에디터는 이 단축키에 '실행 취소' 동작을 연결합니다. `keydown`에 리스너를 설정하고 어떤 키가 눌렸는지 확인할 수 있습니다. -There's a dilemma here: in such a listener, should we check the value of `event.key` or `event.code`? +여기에는 딜레마가 있습니다. 이런 리스너에서는 `event.key` 값을 확인해야 할까요, 아니면 `event.code` 값을 확인해야 할까요? -On one hand, the value of `event.key` is a character, it changes depending on the language. If the visitor has several languages in OS and switches between them, the same key gives different characters. So it makes sense to check `event.code`, it's always the same. +한편으로 `event.key`의 값은 문자이므로 언어에 따라 바뀝니다. 사용자가 OS에 여러 언어를 설정하고 언어를 전환하면, 같은 키가 서로 다른 문자를 만들어냅니다. 따라서 항상 같은 `event.code`를 확인하는 편이 합리적입니다. -Like this: +다음처럼 말입니다. ```js run document.addEventListener('keydown', function(event) { @@ -87,54 +87,54 @@ document.addEventListener('keydown', function(event) { }); ``` -On the other hand, there's a problem with `event.code`. For different keyboard layouts, the same key may have different characters. +반면 `event.code`에도 문제가 있습니다. 키보드 레이아웃이 다르면 같은 키가 서로 다른 문자를 가질 수 있습니다. -For example, here are US layout ("QWERTY") and German layout ("QWERTZ") under it (from Wikipedia): +예를 들어 아래는 미국 레이아웃("QWERTY")과 그 아래 독일 레이아웃("QWERTZ")입니다(Wikipedia 출처). ![](us-layout.svg) ![](german-layout.svg) -For the same key, US layout has "Z", while German layout has "Y" (letters are swapped). +같은 키에 대해 미국 레이아웃은 "Z"를 가지지만, 독일 레이아웃은 "Y"를 가집니다. 문자가 서로 바뀌어 있습니다. -Literally, `event.code` will equal `KeyZ` for people with German layout when they press `key:Y`. +말 그대로 독일 레이아웃을 쓰는 사람이 `key:Y`를 누르면 `event.code`는 `KeyZ`가 됩니다. -If we check `event.code == 'KeyZ'` in our code, then for people with German layout such test will pass when they press `key:Y`. +코드에서 `event.code == 'KeyZ'`를 확인하면, 독일 레이아웃 사용자가 `key:Y`를 눌렀을 때 이 검사를 통과합니다. -That sounds really odd, but so it is. The [specification](https://www.w3.org/TR/uievents-code/#table-key-code-alphanumeric-writing-system) explicitly mentions such behavior. +정말 이상하게 들리지만 실제로 그렇습니다. [명세](https://www.w3.org/TR/uievents-code/#table-key-code-alphanumeric-writing-system)에도 이런 동작이 명시되어 있습니다. -So, `event.code` may match a wrong character for unexpected layout. Same letters in different layouts may map to different physical keys, leading to different codes. Luckily, that happens only with several codes, e.g. `keyA`, `keyQ`, `keyZ` (as we've seen), and doesn't happen with special keys such as `Shift`. You can find the list in the [specification](https://www.w3.org/TR/uievents-code/#table-key-code-alphanumeric-writing-system). +따라서 예상하지 못한 레이아웃에서는 `event.code`가 잘못된 문자와 맞을 수 있습니다. 서로 다른 레이아웃에서 같은 문자가 다른 물리 키에 매핑되어 서로 다른 코드로 이어질 수 있습니다. 다행히 이는 `keyA`, `keyQ`, `keyZ`처럼 몇몇 코드에서만 발생하며, 앞에서 살펴본 경우가 그렇습니다. `Shift` 같은 특수 키에서는 발생하지 않습니다. 목록은 [명세](https://www.w3.org/TR/uievents-code/#table-key-code-alphanumeric-writing-system)에서 확인할 수 있습니다. -To reliably track layout-dependent characters, `event.key` may be a better way. +레이아웃에 따라 달라지는 문자를 안정적으로 추적하려면 `event.key`가 더 나은 방법일 수 있습니다. -On the other hand, `event.code` has the benefit of staying always the same, bound to the physical key location. So hotkeys that rely on it work well even in case of a language switch. +반면 `event.code`는 물리적 키 위치에 묶여 항상 같은 값을 유지한다는 장점이 있습니다. 따라서 이를 기준으로 하는 단축키는 언어가 바뀌어도 잘 동작합니다. -Do we want to handle layout-dependant keys? Then `event.key` is the way to go. +레이아웃에 따라 달라지는 키를 처리하고 싶다면 `event.key`를 사용하면 됩니다. -Or we want a hotkey to work even after a language switch? Then `event.code` may be better. +언어를 전환한 뒤에도 단축키가 동작하길 원한다면 `event.code`가 더 나을 수 있습니다. -## Auto-repeat +## 자동 반복 -If a key is being pressed for a long enough time, it starts to "auto-repeat": the `keydown` triggers again and again, and then when it's released we finally get `keyup`. So it's kind of normal to have many `keydown` and a single `keyup`. +키를 충분히 오래 누르고 있으면 '자동 반복'이 시작됩니다. `keydown`이 계속 반복해서 발생하고, 키를 떼면 마지막에 `keyup`이 발생합니다. 따라서 `keydown`이 여러 번 발생하고 `keyup`이 한 번 발생하는 것은 정상입니다. -For events triggered by auto-repeat, the event object has `event.repeat` property set to `true`. +자동 반복으로 발생한 이벤트의 이벤트 객체에는 `event.repeat` 프로퍼티가 `true`로 설정됩니다. -## Default actions +## 기본 동작 -Default actions vary, as there are many possible things that may be initiated by the keyboard. +키보드로 시작될 수 있는 동작이 많기 때문에 기본 동작도 다양합니다. -For instance: +예를 들면 다음과 같습니다. -- A character appears on the screen (the most obvious outcome). -- A character is deleted (`key:Delete` key). -- The page is scrolled (`key:PageDown` key). -- The browser opens the "Save Page" dialog (`key:Ctrl+S`) -- ...and so on. +- 화면에 문자가 나타납니다. 가장 명확한 결과입니다. +- 문자가 삭제됩니다(`key:Delete` 키). +- 페이지가 스크롤됩니다(`key:PageDown` 키). +- 브라우저가 '페이지 저장' 대화상자를 엽니다(`key:Ctrl+S`). +- 이 밖에도 여러 동작이 있습니다. -Preventing the default action on `keydown` can cancel most of them, with the exception of OS-based special keys. For instance, on Windows `key:Alt+F4` closes the current browser window. And there's no way to stop it by preventing the default action in JavaScript. +`keydown`에서 기본 동작을 막으면 OS 기반 특수 키를 제외한 대부분의 기본 동작을 취소할 수 있습니다. 예를 들어 Windows에서 `key:Alt+F4`는 현재 브라우저 창을 닫습니다. 자바스크립트에서 기본 동작을 막아도 이를 멈출 방법은 없습니다. -For instance, the `` below expects a phone number, so it does not accept keys except digits, `+`, `()` or `-`: +예를 들어 아래 ``은 전화번호를 입력받으므로 숫자, `+`, `()`, `-` 이외의 키는 허용하지 않습니다. ```html autorun height=60 run - + ``` -The `onkeydown` handler here uses `checkPhoneKey` to check for the key pressed. If it's valid (from `0..9` or one of `+-()`), then it returns `true`, otherwise `false`. +여기서 `onkeydown` 핸들러는 `checkPhoneKey`로 눌린 키를 확인합니다. 유효한 키, 즉 `0..9` 범위의 숫자나 `+-()` 중 하나라면 `true`를 반환하고, 그렇지 않으면 `false`를 반환합니다. -As we know, the `false` value returned from the event handler, assigned using a DOM property or an attribute, such as above, prevents the default action, so nothing appears in the `` for keys that don't pass the test. (The `true` value returned doesn't affect anything, only returning `false` matters) +알다시피 위와 같이 DOM 프로퍼티나 속성으로 할당한 이벤트 핸들러에서 `false` 값을 반환하면 기본 동작이 막힙니다. 따라서 검사를 통과하지 못한 키에 대해서는 ``에 아무것도 나타나지 않습니다. `true` 값을 반환해도 아무 영향이 없고, `false` 반환만 중요합니다. -Please note that special keys, such as `key:Backspace`, `key:Left`, `key:Right`, do not work in the input. That's a side effect of the strict filter `checkPhoneKey`. These keys make it return `false`. +`key:Backspace`, `key:Left`, `key:Right` 같은 특수 키가 입력 필드에서 동작하지 않는다는 점에 유의해야 합니다. 이는 엄격한 필터 `checkPhoneKey`의 부작용입니다. 이 키들은 함수가 `false`를 반환하게 만듭니다. -Let's relax the filter a little bit by allowing arrow keys `key:Left`, `key:Right` and `key:Delete`, `key:Backspace`: +방향키 `key:Left`, `key:Right`와 `key:Delete`, `key:Backspace`를 허용해 필터를 조금 완화해 봅시다. ```html autorun height=60 run - + ``` -Now arrows and deletion works well. +이제 화살표 키와 삭제 키가 잘 동작합니다. -Even though we have the key filter, one still can enter anything using a mouse and right-click + Paste. Mobile devices provide other means to enter values. So the filter is not 100% reliable. +키 필터가 있더라도 마우스 오른쪽 클릭 + 붙여넣기를 사용하면 여전히 무엇이든 입력할 수 있습니다. 모바일 기기는 값을 입력하는 다른 수단도 제공합니다. 따라서 이 필터를 100% 신뢰할 수는 없습니다. -The alternative approach would be to track the `oninput` event -- it triggers *after* any modification. There we can check the new `input.value` and modify it/highlight the `` when it's invalid. Or we can use both event handlers together. +대안은 `oninput` 이벤트를 추적하는 것입니다. 이 이벤트는 어떤 수정이든 일어난 *후에* 발생합니다. 여기서 새로운 `input.value`를 확인하고, 유효하지 않으면 값을 수정하거나 ``을 강조할 수 있습니다. 또는 두 이벤트 핸들러를 함께 사용할 수도 있습니다. -## Legacy +## 레거시 -In the past, there was a `keypress` event, and also `keyCode`, `charCode`, `which` properties of the event object. +과거에는 `keypress` 이벤트와 이벤트 객체의 `keyCode`, `charCode`, `which` 프로퍼티가 있었습니다. -There were so many browser incompatibilities while working with them, that developers of the specification had no way, other than deprecating all of them and creating new, modern events (described above in this chapter). The old code still works, as browsers keep supporting them, but there's totally no need to use those any more. +이것들을 사용할 때 브라우저 간 비호환성이 너무 많았기 때문에, 명세 개발자들은 이들을 모두 역사의 뒤안길로 보내고 위에서 설명한 새롭고 현대적인 이벤트를 만드는 것 외에는 방법이 없었습니다. 브라우저가 계속 지원하므로 오래된 코드는 여전히 동작하지만, 이제 더 이상 사용할 필요는 전혀 없습니다. -## Mobile Keyboards +## 모바일 키보드 -When using virtual/mobile keyboards, formally known as IME (Input-Method Editor), the W3C standard states that a KeyboardEvent's [`e.keyCode` should be `229`](https://www.w3.org/TR/uievents/#determine-keydown-keyup-keyCode) and [`e.key` should be `"Unidentified"`](https://www.w3.org/TR/uievents-key/#key-attr-values). +공식적으로 IME(Input-Method Editor)라고 알려진 가상·모바일 키보드를 사용할 때, W3C 표준에 따르면 KeyboardEvent의 [`e.keyCode`는 `229`여야 하고](https://www.w3.org/TR/uievents/#determine-keydown-keyup-keyCode) [`e.key`는 `"Unidentified"`여야 합니다](https://www.w3.org/TR/uievents-key/#key-attr-values). -While some of these keyboards might still use the right values for `e.key`, `e.code`, `e.keyCode`... when pressing certain keys such as arrows or backspace, there's no guarantee, so your keyboard logic might not always work on mobile devices. +이런 키보드 중 일부는 방향키나 백스페이스 같은 특정 키를 누를 때 `e.key`, `e.code`, `e.keyCode` 등에 올바른 값을 사용할 수도 있지만 보장되지는 않습니다. 따라서 키보드 로직이 모바일 기기에서 항상 동작하지 않을 수 있습니다. -## Summary +## 요약 -Pressing a key always generates a keyboard event, be it symbol keys or special keys like `key:Shift` or `key:Ctrl` and so on. The only exception is `key:Fn` key that sometimes presents on a laptop keyboard. There's no keyboard event for it, because it's often implemented on lower level than OS. +키를 누르면 기호 키든 `key:Shift`, `key:Ctrl` 같은 특수 키든 항상 키보드 이벤트가 발생합니다. 유일한 예외는 노트북 키보드에 가끔 있는 `key:Fn` 키입니다. 이 키는 OS보다 낮은 수준에서 구현되는 경우가 많기 때문에 키보드 이벤트가 없습니다. -Keyboard events: +키보드 이벤트는 다음과 같습니다. -- `keydown` -- on pressing the key (auto-repeats if the key is pressed for long), -- `keyup` -- on releasing the key. +- `keydown` -- 키를 누를 때 발생합니다. 키를 오래 누르면 자동 반복됩니다. +- `keyup` -- 키를 뗄 때 발생합니다. -Main keyboard event properties: +주요 키보드 이벤트 프로퍼티는 다음과 같습니다. -- `code` -- the "key code" (`"KeyA"`, `"ArrowLeft"` and so on), specific to the physical location of the key on keyboard. -- `key` -- the character (`"A"`, `"a"` and so on), for non-character keys, such as `key:Esc`, usually has the same value as `code`. +- `code` -- `"KeyA"`, `"ArrowLeft"` 같은 '키 코드'입니다. 키보드에서 키의 물리적 위치에 따라 정해집니다. +- `key` -- `"A"`, `"a"` 같은 문자입니다. `key:Esc` 같은 비문자 키에서는 보통 `code`와 같은 값을 가집니다. -In the past, keyboard events were sometimes used to track user input in form fields. That's not reliable, because the input can come from various sources. We have `input` and `change` events to handle any input (covered later in the chapter ). They trigger after any kind of input, including copy-pasting or speech recognition. +과거에는 폼 필드의 사용자 입력을 추적하는 데 키보드 이벤트를 사용하기도 했습니다. 하지만 입력은 다양한 출처에서 올 수 있으므로 신뢰할 수 없습니다. 모든 입력을 처리하려면 `input`과 `change` 이벤트를 사용합니다. 이는 챕터에서 나중에 다룹니다. 이 이벤트들은 복사·붙여넣기나 음성 인식을 포함한 모든 종류의 입력이 일어난 뒤에 발생합니다. -We should use keyboard events when we really want keyboard. For example, to react on hotkeys or special keys. +정말로 키보드를 다루고 싶을 때 키보드 이벤트를 사용해야 합니다. 예를 들어 단축키나 특수 키에 반응할 때 사용합니다. \ No newline at end of file diff --git a/2-ui/3-event-details/8-onscroll/article.md b/2-ui/3-event-details/8-onscroll/article.md index 734bd84c61..0805420a81 100644 --- a/2-ui/3-event-details/8-onscroll/article.md +++ b/2-ui/3-event-details/8-onscroll/article.md @@ -1,12 +1,12 @@ -# Scrolling +# 스크롤 -The `scroll` event allows reacting to a page or element scrolling. There are quite a few good things we can do here. +`scroll` 이벤트를 사용하면 페이지나 요소가 스크롤될 때 반응할 수 있습니다. 이를 활용해 할 수 있는 유용한 일이 꽤 많습니다. -For instance: -- Show/hide additional controls or information depending on where in the document the user is. -- Load more data when the user scrolls down till the end of the page. +예를 들면 다음과 같습니다. +- 문서에서 사용자가 어느 위치에 있는지에 따라 추가 컨트롤이나 정보를 표시하거나 숨깁니다. +- 사용자가 페이지 끝까지 아래로 스크롤하면 더 많은 데이터를 불러옵니다. -Here's a small function to show the current scroll: +현재 스크롤 위치를 보여주는 작은 함수는 다음과 같습니다. ```js autorun window.addEventListener('scroll', function() { @@ -15,23 +15,23 @@ window.addEventListener('scroll', function() { ``` ```online -In action: +실제 동작은 다음과 같습니다. -Current scroll = scroll the window +현재 스크롤 위치 = 창을 스크롤해 보세요 ``` -The `scroll` event works both on the `window` and on scrollable elements. +`scroll` 이벤트는 `window`와 스크롤 가능한 요소 모두에서 동작합니다. -## Prevent scrolling +## 스크롤 막기 -How do we make something unscrollable? +무언가를 스크롤되지 않게 하려면 어떻게 해야 할까요? -We can't prevent scrolling by using `event.preventDefault()` in `onscroll` listener, because it triggers *after* the scroll has already happened. +`onscroll` 리스너에서 `event.preventDefault()`를 사용해 스크롤을 막을 수는 없습니다. 이 이벤트는 스크롤이 이미 일어난 *후에* 발생하기 때문입니다. -But we can prevent scrolling by `event.preventDefault()` on an event that causes the scroll, for instance `keydown` event for `key:pageUp` and `key:pageDown`. +하지만 스크롤을 일으키는 이벤트에서 `event.preventDefault()`를 호출하면 스크롤을 막을 수 있습니다. 예를 들어 `key:pageUp`과 `key:pageDown`에 대한 `keydown` 이벤트가 있습니다. -If we add an event handler to these events and `event.preventDefault()` in it, then the scroll won't start. +이 이벤트에 이벤트 핸들러를 추가하고 그 안에서 `event.preventDefault()`를 호출하면 스크롤은 시작되지 않습니다. -There are many ways to initiate a scroll, so it's more reliable to use CSS, `overflow` property. +스크롤을 시작하는 방법은 많으므로 CSS의 `overflow` 프로퍼티를 사용하는 편이 더 안정적입니다. -Here are few tasks that you can solve or look through to see applications of `onscroll`. +아래 과제에서는 `onscroll`의 활용 사례를 직접 풀어보거나 살펴볼 수 있습니다. \ No newline at end of file diff --git a/2-ui/5-loading/03-onload-onerror/article.md b/2-ui/5-loading/03-onload-onerror/article.md index 590e54ab40..d3bdde5886 100644 --- a/2-ui/5-loading/03-onload-onerror/article.md +++ b/2-ui/5-loading/03-onload-onerror/article.md @@ -1,17 +1,17 @@ -# Resource loading: onload and onerror +# onload와 onerror -The browser allows us to track the loading of external resources -- scripts, iframes, pictures and so on. +브라우저에서는 스크립트, iframe, 이미지 같은 외부 리소스의 로딩을 추적할 수 있습니다. -There are two events for it: +이를 위한 이벤트는 두 가지입니다. -- `onload` -- successful load, -- `onerror` -- an error occurred. +- `onload` -- 성공적으로 로드됨 +- `onerror` -- 에러 발생 -## Loading a script +## 스크립트 로딩 -Let's say we need to load a third-party script and call a function that resides there. +서드 파티 스크립트를 로드하고 그 안에 있는 함수를 호출해야 한다고 가정해 봅시다. -We can load it dynamically, like this: +다음과 같이 동적으로 로드할 수 있습니다. ```js let script = document.createElement('script'); @@ -20,46 +20,46 @@ script.src = "my.js"; document.head.append(script); ``` -...But how to run the function that is declared inside that script? We need to wait until the script loads, and only then we can call it. +그런데 그 스크립트 안에 선언된 함수는 어떻게 실행할까요? 스크립트가 로드될 때까지 기다린 다음에야 호출할 수 있습니다. ```smart -For our own scripts we could use [JavaScript modules](info:modules) here, but they are not widely adopted by third-party libraries. +직접 작성한 스크립트라면 여기서 [자바스크립트 모듈](info:modules)을 사용할 수 있지만, 서드 파티 라이브러리에서는 아직 널리 쓰이지 않습니다. ``` ### script.onload -The main helper is the `load` event. It triggers after the script was loaded and executed. +주요 도우미는 `load` 이벤트입니다. 이 이벤트는 스크립트가 로드되고 실행된 뒤 발생합니다. -For instance: +예를 들면 다음과 같습니다. ```js run untrusted let script = document.createElement('script'); -// can load any script, from any domain +// 어떤 도메인에서든 어떤 스크립트든 로드할 수 있습니다 script.src = "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.3.0/lodash.js" document.head.append(script); *!* script.onload = function() { - // the script creates a variable "_" - alert( _.VERSION ); // shows library version + // 스크립트는 변수 "_"를 만듭니다 + alert( _.VERSION ); // 라이브러리 버전을 보여줍니다 }; */!* ``` -So in `onload` we can use script variables, run functions etc. +따라서 `onload` 안에서는 스크립트 변수 사용, 함수 실행 등을 할 수 있습니다. -...And what if the loading failed? For instance, there's no such script (error 404) or the server is down (unavailable). +그렇다면 로딩이 실패하면 어떻게 될까요? 예를 들어 그런 스크립트가 없거나(404 에러) 서버가 다운되어 사용할 수 없는 경우입니다. ### script.onerror -Errors that occur during the loading of the script can be tracked in an `error` event. +스크립트를 로딩하는 중에 발생하는 에러는 `error` 이벤트로 추적할 수 있습니다. -For instance, let's request a script that doesn't exist: +예를 들어 존재하지 않는 스크립트를 요청해 봅시다. ```js run let script = document.createElement('script'); -script.src = "https://example.com/404.js"; // no such script +script.src = "https://example.com/404.js"; // 그런 스크립트는 없습니다 document.head.append(script); *!* @@ -69,57 +69,57 @@ script.onerror = function() { */!* ``` -Please note that we can't get HTTP error details here. We don't know if it was an error 404 or 500 or something else. Just that the loading failed. +여기서는 HTTP 에러의 세부 정보를 얻을 수 없다는 점에 유의해야 합니다. 404 에러였는지, 500 에러였는지, 아니면 다른 에러였는지는 알 수 없습니다. 로딩이 실패했다는 사실만 알 수 있습니다. ```warn -Events `onload`/`onerror` track only the loading itself. +`onload`·`onerror` 이벤트는 로딩 자체만 추적합니다. -Errors that may occur during script processing and execution are out of scope for these events. That is: if a script loaded successfully, then `onload` triggers, even if it has programming errors in it. To track script errors, one can use `window.onerror` global handler. +스크립트를 처리하고 실행하는 중에 발생할 수 있는 에러는 이 이벤트의 범위 밖입니다. 즉 스크립트가 성공적으로 로드되면, 그 안에 프로그래밍 에러가 있더라도 `onload`가 발생합니다. 스크립트 에러를 추적하려면 전역 핸들러 `window.onerror`를 사용할 수 있습니다. ``` -## Other resources +## 기타 리소스 -The `load` and `error` events also work for other resources, basically for any resource that has an external `src`. +`load`와 `error` 이벤트는 다른 리소스에서도 동작합니다. 기본적으로 외부 `src`가 있는 모든 리소스에서 동작합니다. -For example: +예를 들면 다음과 같습니다. ```js run let img = document.createElement('img'); img.src = "https://js.cx/clipart/train.gif"; // (*) img.onload = function() { - alert(`Image loaded, size ${img.width}x${img.height}`); + alert(`이미지가 로드되었습니다. 크기 ${img.width}x${img.height}`); }; img.onerror = function() { - alert("Error occurred while loading image"); + alert("이미지를 로드하는 중 에러가 발생했습니다"); }; ``` -There are some notes though: +다만 몇 가지 참고할 점이 있습니다. -- Most resources start loading when they are added to the document. But `` is an exception. It starts loading when it gets a src `(*)`. -- For `