Skip to content
This page has been auto-translated and may contain errors.View in English

이벤트

docs.scrimba.com

반응하지 않는 페이지는 단순한 문서일 뿐입니다. 사람이 버튼을 클릭하거나, 검색창에 입력하거나, 을 제출할 때 무언가 일어나기를 원하는 순간, "이것이 일어나면, 이 코드를 실행해"라고 말할 방법이 필요합니다. 그것이 바로 이벤트입니다. 이 장은 사용자가 하는 일을 듣고 그에 반응하는 것에 관한 것입니다.

이벤트 듣기

**이벤트**는 페이지에서 일어나는 무언가입니다: 클릭, 키 누르기, 폼 제출. 이벤트에 반응하려면, 요소를 선택하고, 관심 있는 이벤트의 이름을 지정한 후, 실행할 함수를 넘겨줍니다.

그 함수를 핸들러라고 합니다. 이를 연결하는 메서드는 addEventListener입니다:

js
const button = document.querySelector(".buy-button");

button.addEventListener("click", () => {
  console.log("누군가 구매를 클릭했습니다");
});

왼쪽에서 오른쪽으로 읽으세요: 이 버튼에서 "click"을 듣고, 일어나면 이 함수를 실행합니다. 핸들러는 한 번이 아니라 이벤트가 일어날 때마다 실행됩니다. 3번 클릭하면 3번 실행됩니다.

**이벤트**는 무언가 일어날 때 브라우저가 발생시키는 신호입니다: 사용자가 클릭하거나, 입력하거나, 폼을 제출하거나, 페이지가 로드를 완료합니다. addEventListener로 핸들러를 등록해서 반응하며, 이는 이벤트 이름을 문자열로, 그리고 발생할 때마다 호출할 함수를 받습니다.

js
const button = document.querySelector(".buy-button");

const handleBuy = () => {
  console.log("누군가 구매를 클릭했습니다");
};

button.addEventListener("click", handleBuy);

handleBuy가 괄호 없이 전달되는 것을 주목하세요. 지금 호출하는 것이 아니라 나중에 호출하도록 함수 자체를 브라우저에 넘겨주는 것입니다. addEventListener("click", handleBuy())라고 작성하면 즉시 호출되고 반환값을 등록하게 되는데, 이는 초보자가 흔히 하는 실수입니다.

**이벤트**는 브라우저가 그것에 관심을 등록한 코드에 전송하는 메시지입니다. addEventListener(type, handler)로 등록합니다: type은 이벤트 이름을 문자열로, handler는 그 요소에서 이벤트가 발생할 때마다 브라우저가 호출하는 콜백입니다.

js
const button = document.querySelector(".buy-button");

const handleBuy = () => {
  console.log("누군가 구매를 클릭했습니다");
};

button.addEventListener("click", handleBuy);

두 가지가 중요합니다. 첫째, handleBuy()(호출 결과)가 아니라 handleBuy(함수 값)을 전달합니다. 둘째, addEventListener는 가산적입니다: 두 함수로 두 번 호출하면 둘 다 실행되므로 리스너가 쌓입니다. 기존 하나를 덮어씁니다. 이것이 단일 핸들러만 보유하는 button.onclick을 할당하는 대신 존재하는 실용적인 이유입니다. 나중에 제거하고 싶을 때를 위해 핸들러에 대한 명명된 참조를 유지하는 것도 중요합니다.

핸들러는 일반적인 함수이고, 첨부하는 요소는 DOM에서 나옵니다. 요소를 선택하고 함수를 작성할 수 있다면, 사용자가 요소에 하는 일에 반응할 수 있습니다.

Juno이벤트 듣기 사용자에게 반응하려면, 요소를 선택하고 이벤트를 "click"같은 문자열로 명명한 후, addEventListener에 실행할 함수를 제공합니다. 그 함수는 핸들러이며, 한 번이 아니라 이벤트가 일어날 때마다 실행됩니다. 이 하나의 메서드가 페이지가 당신에게 반응하는 거의 모든 것 뒤에 있습니다.
Juno이벤트 듣기addEventListener는 이벤트 이름과 함수를 받으며, 이벤트가 발생할 때마다 그 함수를 호출합니다. 괄호 없이 함수의 이름으로 전달합니다: handleBuy, handleBuy()가 아닙니다. 괄호를 추가하면 클릭 대신 지금 호출되고, 거의 모든 사람이 한 번은 이것에 걸립니다.
Juno이벤트 듣기addEventListener는 브라우저가 일치하는 각 이벤트에서 발생하는 콜백을 등록하며, 덮어쓰는 것이 아니라 쌓으므로 onclick보다 선호합니다. 함수 값을 전달하지, 호출 결과가 아닙니다: handleBuy이지 handleBuy()가 아닙니다. 리스너를 제거할 시간이 되었을 때를 대비해 명명된 참조도 유지하세요.

이벤트 객체

브라우저가 핸들러를 실행할 때, 한 가지 정보를 넘겨줍니다: 일어난 일을 설명하는 이벤트 객체. 핸들러에 매개변수를 주어 이를 잡으세요, 보통 event라고 이름 지습니다:

js
const button = document.querySelector(".buy-button");

button.addEventListener("click", (event) => {
  console.log(event.target); // 클릭된 요소
});

가장 유용한 부분은 event.target: 이벤트가 일어난 요소입니다. 클릭이 버튼에 있었다면, event.target은 그 버튼입니다. 다시 선택할 필요가 없습니다, 이벤트가 이미 출처를 알려줍니다.

모든 핸들러는 하나의 인수를 받습니다: 일어난 일에 대한 세부 정보를 담은 이벤트 객체. 매개변수의 이름을 지어서 캡처하세요, 관례상 event (또는 e):

js
const search = document.querySelector(".search-input");

search.addEventListener("input", (event) => {
  console.log(event.target.value); // 사용자가 지금까지 입력한 것
});

event.target은 이벤트가 발생한 요소입니다. 폼 필드에서 이는 주인공입니다, event.target.value는 입력의 현재 텍스트를 제공하기 때문입니다. 그 쌍, input 이벤트와 event.target.value는 누군가 입력하면서 입력하는 것을 읽는 방법입니다.

브라우저는 핸들러에 하나의 인수를 전달합니다: 일어난 일의 스냅샷인 이벤트 객체: 어느 요소, 어느 키, 마우스 위치, 그리고 이벤트의 기본 동작을 제어하는 메서드. 매개변수로 캡처하세요, 관례상 event.

js
const search = document.querySelector(".search-input");

search.addEventListener("input", (event) => {
  console.log(event.target.value); // 필드의 현재 텍스트
});

event.target은 이벤트를 시작한 요소이며, 항상 리스너를 첨부한 요소는 아닙니다 (그것은 event.currentTarget이며, 그들 사이의 간격이 아래의 위임을 작동하게 합니다). 폼 컨트롤에서, event.target.value는 현재 값을 문자열로 읽습니다, 따라서 HTML이 텍스트로 보유하는 같은 .value가 여기서 텍스트로 돌아옵니다. 숫자를 원하면 Number(event.target.value)로 자신이 변환합니다.

Juno이벤트 객체 핸들러는 하나의 인수, 이벤트 객체를 받으므로 event라는 매개변수를 주어 이를 잡으세요. 가장 많이 사용할 부분은 event.target이며, 이벤트가 일어난 요소입니다. 다시 선택할 필요가 없습니다, 이벤트가 이미 출처를 알고 있습니다.
Juno이벤트 객체event라는 매개변수의 이름을 지으면 브라우저가 일어난 일의 세부 정보로 채웁니다. event.target은 발생한 요소이고, input에서 event.target.value는 필드의 현재 텍스트입니다. input 이벤트를 event.target.value와 쌍으로 하면 누군가 입력하면서 입력하는 것을 읽을 수 있습니다.
Juno이벤트 객체 이벤트 객체는 일어난 일의 스냅샷이고, event.target은 시작한 곳이며, 항상 리스너를 첨부한 곳은 아닙니다; 그것은 event.currentTarget입니다. 폼 필드에서 event.target.value는 문자열로 돌아오므로, 숫자가 필요할 때 Number(...)로 감싸세요. target-versus-currentTarget 분할을 염두에 두세요, 위임이 이를 활용하기 때문입니다.

일반적인 이벤트

몇 가지 이벤트가 대부분 구축할 것을 다룹니다:

  • click: 사용자가 무언가를 클릭하거나 탭합니다.
  • input: 텍스트 필드의 값이 입력할 때 변합니다.
  • submit: 폼이 제출됩니다.
  • keydown: 키가 눌러집니다.

까다로운 것은 submit입니다. 기본적으로 폼을 제출하면 페이지가 다시 로드되어 JavaScript가 하고 있던 모든 것이 지워집니다. 이를 중지하려면 핸들러 안에서 event.preventDefault()를 호출하세요:

js
const form = document.querySelector("form");

form.addEventListener("submit", (event) => {
  event.preventDefault(); // 페이지가 다시 로드되는 것을 중지합니다
  console.log("폼이 제출되었습니다, 페이지가 그대로 있습니다");
});

대부분의 페이지는 작은 이벤트 세트를 활용합니다: 버튼에는 click, 텍스트 필드 변경에는 input, 폼에는 submit, 키보드 단축키에는 keydown. 이 네 가지를 배우면 대부분의 상호 작용을 구축할 수 있습니다.

사람들을 놀라게 하는 것은 submit입니다. 폼의 기본 동작은 페이지를 다시 로드하거나 다른 곳으로 이동하는 것이며, 이는 코드가 처리하던 것을 버립니다. event.preventDefault()를 호출해서 페이지를 제자리에 유지하고 자신이 처리합니다:

js
const form = document.querySelector("form");

const handleSubmit = (event) => {
  event.preventDefault();
  const email = form.querySelector(".email-input").value;
  console.log(`${email}에 가입 중`);
};

form.addEventListener("submit", handleSubmit);

버튼의 click이 아니라 폼 자체에서 submit을 들으세요, 그래야 Enter를 누르는 키보드 사용자도 포함됩니다.

네 가지 이벤트가 대부분의 상호 작용을 수행합니다: click, input (blur를 기다리는 change와 달리 모든 값 변경에서 발생), submit, 및 keydown. 올바른 요소에 바인딩하면 대부분의 UI가 그로부터 나옵니다.

submit 이벤트는 preventDefault가 그 자리를 얻는 곳입니다. 폼의 기본 동작은 전체 네비게이션이며, 페이지 내 상태를 버립니다. event.preventDefault()를 호출하면 취소되어 데이터를 직접 처리합니다:

js
const form = document.querySelector("form");

const handleSubmit = (event) => {
  event.preventDefault();
  const email = form.querySelector(".email-input").value;
  console.log(`${email}에 가입 중`);
  // 어딘가에 보내는 것은 다음 장의 일입니다
};

form.addEventListener("submit", handleSubmit);

버튼의 click이 아니라 폼의 submit에 첨부하세요: submit은 Enter 키, 버튼 클릭, 프로그래밍 방식의 제출 등 모두에서 발생하므로 올바른 훅입니다. 값을 얻으면, 어딘가에 보내는 것은 async 코드가 필요한 곳이며, 이것이 다음 장입니다.

버블링과 위임

요소를 클릭하면, 이벤트가 거기서 멈추지 않습니다. **버블**합니다: 클릭된 요소에서 발생한 후, 그 부모, 그 부모의 부모, 모두 위쪽으로 올라갑니다. 이것이 부모의 리스너가 자식 클릭을 듣는 이유입니다.

그 동작은 위임을 지원합니다: 부모에 하나의 리스너를 첨부하고 event.target을 사용해서 실제로 클릭된 자식을 찾습니다. 항목당 하나의 리스너 대신, 모두를 다루는 하나를 얻습니다.

js
const list = document.querySelector(".todo-list");

list.addEventListener("click", (event) => {
  if (event.target.matches(".delete")) {
    event.target.closest("li").remove();
  }
});

보상: 이것은 나중에 목록에 추가된 항목을 처리합니다. 항목당 리스너는 현재 존재하는 요소만 바인딩합니다; 부모의 위임 리스너는 코드가 실행될 때 존재하지 않았던 자식 클릭을 잡습니다, 이벤트가 여전히 듣는 부모로 버블 올라가기 때문입니다.

리스너 제거

removeEventListener는 핸들러를 분리하지만, 추가한 정확한 함수 참조를 전달할 경우에만:

js
const button = document.querySelector(".buy-button");

button.addEventListener("click", handleBuy);
button.removeEventListener("click", handleBuy); // 작동: 같은 참조

이것이 익명 핸들러를 제거할 수 없는 이유입니다. addEventListener("click", () => {...})같은 인라인 화살표 함수는 매번 새로운 함수를 만들므로, removeEventListener에 전달할 참조가 없고, 리스너는 막혀있습니다. 제거할 계획인 명명된 핸들러가 이를 피합니다. 접촉하는 요소보다 오래 사는 리스너는 실제 메모리 누수 소스입니다, 리스너가 여전히 그들을 지적하기 때문에 페이지가 더 이상 필요하지 않은 객체를 회수할 수 없습니다.

하나 더의 성능 참고사항: 스크롤 또는 터치 리스너에서 세 번째 인수로 { passive: true }를 추가하면 preventDefault를 호출하지 않을 것을 약속하며, 이는 브라우저가 핸들러를 기다리지 않고 스크롤할 수 있게 하고 스크롤을 부드럽게 유지합니다.

Juno일반적인 이벤트 가장 많이 사용할 이벤트는 click, input, submit, 및 keydown입니다. 기억할 것은 submit: 폼은 기본적으로 페이지를 다시 로드하므로 핸들러에서 event.preventDefault()를 호출해서 이를 중지하고 제어를 유지하세요. 놓치면 페이지가 당신 아래에서 새로 고쳐지며, 이는 처음에는 혼동합니다.
Juno일반적인 이벤트click, input, submit, 및 keydown은 대부분 구축하는 것을 다룹니다. 버튼의 click이 아니라 폼에서 submit을 들으세요, 그래야 키보드 사용자가 Enter를 사용할 수 있습니다. 그리고 submit 핸들러에서 event.preventDefault()를 호출하거나 페이지가 다시 로드되고 상태를 가져갑니다.
Juno일반적인 이벤트 이벤트는 부모로 버블 올라가므로, 하나의 위임 리스너와 event.target은 나중에 추가되는 것들을 포함해 많은 자식을 다룹니다. removeEventListener는 추가한 것과 같은 함수 참조를 필요로 하므로, 익명 핸들러는 절대 제거할 수 없고 메모리를 누수할 수 있습니다. 그리고 submit은 버튼의 click을 이기는데 Enter에도 발생하기 때문입니다; 다시 로드를 중지하기 위해 거기서 event.preventDefault()를 유지하세요.

이벤트 다음은 어디인가요

이벤트는 페이지가 듣는 방식입니다. 요소를 선택하고, 관심 있는 것의 이름을 지정하고, 일어나면 함수를 실행하며, 진행하면서 이벤트 객체의 세부 정보를 읽습니다. 거의 모든 대화형 기능이 그 루프로부터 구축됩니다.

자연스러운 다음 단계는 핸들러에서 느린 작업을 수행하는 것입니다, 폼을 서버에 보내거나 새 데이터를 로드하는 것처럼, 페이지를 멈추지 않고. 그것이 async 코드가 하는 것이며, 다음 장입니다. 객체에서 유지하는 항목 목록과 같은 구조화된 데이터에 도달하는 핸들러는 이미 알고 있는 것도 활용합니다.