[JavaScript] Ch10. Events

jinjoo-jung·2023년 8월 6일

JavaScript

목록 보기
12/17

이벤트 추가 및 제거

.addEventListner()

  • 대상에 이벤트 청취(Listen)를 등록한다
  • 대상에 지정한 이벤트가 발생했을 때 지정한 함수(Handler)가 호출된다.
const parentEl = document.querySelector('.parent')
const childEl = document.querySelector('.child')

parentEl.addEventListener('click', () => {
    console.log('Parent!')
})
childEl.addEventListener('click', () => {
    console.log('Child!')
})

-> 실제 parent 요소를 클릭했을 때 두 번째 인수의 콜백 함수가 호출되면서 console.log가 실행이 된다.
-> EventListner란, 이벤트가 발생하는지를 듣고 있는자. (이벤트 청취)
-> 실제 지정된 함수가 호출이 되는데 이 때 지정된 함수는 핸들러라고 한다.

.removeEventListner()

  • 대상에 등록했던 이벤트 청취를 제거
  • 메모리 관리를 위해 등록한 이벤트를 제거하는 과정이 필요할 수 있다.
const handler = () => {
    console.log('Parent!')
}
parentEl.addEventListener('click', handler)
childEl.addEventListener('click', () => {
    parentEl.removeEventListener('click', handler)
})

-> 우리가 removeEventListner를 통해서 언젠가 해당함수를 제거할 것이라면 특정 변수에 함수를 할당해서 사용해야 add, remove로 전달을 해서 제거를 할 수 있다.

이벤트 객체

이벤트 객체란, 대상에서 발생한 이벤트 정보를 담고있다.

  • target 속성은, 이벤트가 발생한 해당 요소
  • currentTarget 속성은, 이벤트가 등록된 요소
  • 사용할 수 있는 이벤트는 'click' , 'wheel' , 키보드의 키를 누르는 'keydown'
const inputEl = document.querySelector('input')
const childEl = document.querySelector('.child')

inputEl.addEventListener('keydown', event => {
    console.log(event.key)
})

기본 동작 방지

  • 여기서 기본 동작이라는 것은 브라우저에서 제공하는 동작을 말한다. 대표적으로 요소에서 위아래로 화면을 스크롤 하거나 a 태그로 화면을 이동하는 등 모두 기본 동작에 해당된다.

  • 이러한 기본 동작들을 html, css만 작성하더라도 쓸 수 있는 동작인데 js에서 사용하지 못 하도록
    방지시켜줄 수 있다.

  • 마우스 휠의 스크롤 동작 방지

const parentEl = document.querySelector('.parent')

parentEl.addEventListener('wheel', event => {
    event.preventDefault()
    console.log('Wheel!')
})

-> 위 코드는 Wheel이라는 문자는 출력이 되지만 실제 화면은 움직이지 않는다.
기본 동작 방지는, 해당 이벤트가 발생하는 것을 막는 것이 아닌, 브라우저가 가지고 있는 동작만 방지하는 것이다. 이러한 기본적인 동작이 화면에 parent요소 scroll을 보여지지 않게 하는 것이다.

  • a 태그에서 페이지 이동 방지!
    -> 문자는 출력이 되지만, 화면이 걸어놓은 링크로 넘어가지는 않는다.

버블링과 캡쳐링

  • 이벤트 전파(버블링) 정지
    -> 콘솔에 출력될 때 점점 넓은 범위로 이벤트가 올라가면서 발생(이벤트 버블링)
    a 태그 < child < parent < body < window
  • 이렇게 전파가 되는데 중간에 정지를 할 수 있는데.
event.stopPropagation()   // 버블링 정지!

parent에 버블링 정지를 걸어 놓으면, a 태그를 클릭하면 a, child, parent 까지만 출력이 된다.

  • 이렇게 이벤트는 상위 요소로 전파되는 성질을 가지고 있기 때문에 의도치 않은 내용이 동작이 실행되는 것을 방지하기 위해서 사용되는 유용한 메소드이다.

이벤트 캡쳐

위 사진을 보면, child를 클릭해도 캡쳐를 걸어둔 Body가 먼저 출력되는 것을 볼 수 있다.

  • 캡쳐가 두 부분에 걸려있어도 먼저 출력 된후 에 출력된다.
    ex. window, body, parent에 모두 출력을 걸어두고 child를 클릭하게 되면

    위와 같은 결과가 나온다.
    => 잘 알고있어야 이벤트들을 제대로 관리할 수 있다.
  • stopPropagation을 이벤트 버블링, 캡쳐링에서도 다 사용할 수 있다.

주의!!


const parentEl = document.querySelector('.parent')
const handler = () => {
    console.log('Parent!')
}

parentEl.addEventListener('click', handler, {
    capture: true
})
parentEl.removeEventListener('click', handler)
  • addEventListener로 이벤트 청취를 추가할 때, 만약 캡쳐옵션을 추가했다면removeEventListener 에도 동일하게 캡쳐옵션을 추가해야 한다.

이벤트 옵션

  1. 핸들러 한 번만 실행
const parentEl = document.querySelector('.parent')

parentEl.addEventListener('click', event => {
    conssol.log('Parent!')
}, {
    once :true
})

-> 한 번만 출력이 된다.

  1. 기본 동작과 핸들러 실행 분리
const parentEl = document.querySelector('.parent')

parentEl.addEventListener('wheel', ()=> {
    for(let i =0; i < 10000; i+=1) {
        console.log(i)
    }
} , {
    passive:true
})

=> 장점 : parent요소의 마우스 휠을 통한 스크롤의 기본 동작과 내부에 처리해야하는 복잡한 로직의 실행을 분리하기 때문에 화면이 훨씬 부드럽게 동작한다. => 사용성이 좋아짐

이벤트 위임(Delegation)

  • 이벤트를 특정 대상에다가 직접 부여하는 것이 아닌 그 대상의 조상 요소에, 위임을 해서 이벤트를 한 번에 제어할 수 있는 패턴을 사용
  • 비슷한 패턴의 여러 요소에서 이벤트를 핸들링해야 하는 경우, 그 여러 요소에 직접적으로 이벤트를 하나씩 부여하는 것이 아닌, 단일 조상 요소에서 제어하는 이벤트 위임 패턴을 사용할 수 있다.
const parentEl = document.querySelector('.parent')
const childEls = document.querySelectorAll('.child')
// 이때 document.querySelectorAll은 노드 리스트를 반환

// 모든 대상 요소에 이벤트 등록!
childEls.forEach(el => {
    el.addEventListener('click', event => {
        console.log(event.target.textContet)
    })
})

// 조상 요소에 이벤트 위엄!
parentEl.addEventListener('click', event => {
    const childEl = event.target.closest('.child')
    if(childEl) {
        console.log(childEl.textContet)
    }
})

--> event.target이라는 속성은 실제로 이벤트가 발생한 그 요소이고, 그 요소에 child라는 클래스가 있거나 가까운 조상 요소에도 child 라는 클래스가 있으면 결과적으로 child를 클릭한 것과 동일하므로 child요소를 찾아서 그 child요소에서 textcontent를 출력한다.
---> js을 통해서 click이벤트가 발생하는지 들어야 하는 요소가 여러 개에서 하나로 줄어들기 때문에 훨씬 애플리케이션을 효율적으로 관리할 수 있다 .

Mouse & Pointer Events

  • click : 클릭했을 때

  • dbclick : 더블 클릭했을 때

  • mousedown : 버튼을 누를 때

  • mouseup : 버튼을 땔 때

  • mouseenter : 포인터가 요소 위로 들어갈 때

  • mouseleave : 포인터가 요소 밖으로 나올 때

  • mousemove : 포인터가 움직일 때

  • contextmenu : 우클릭했을 때

  • wheel : 휠 버튼이 회전할 때

  • deltaY 속성의 값이 양수이면 스크롤 방향이 아래로 내려가고 있는 상황/ 음수면 올라가고 있는 상황

키보드 이벤트

  • keydown : 키를 누를 때
  • keyup : 키를 떌 때

event.target은 이벤트가 발생한 그 대상을 의미하므로 input요소에서 키보드를 누를 것이기 때문에 event.target은 input요소이고 input요소가 가지고 있는 입력된 값을 value라는 속성을 통해서 알아낼 수 있다.

  • 한국어 일본어 중국어는 처리하는 과정이 두번 일어나는데 이러한 문자를 CJK 문자라고 한다.
  • 이러한 CJK 문자가 처리되는 중간의 과정을 알아낼 수 있는데(console.log(event.isComposing)은 CJK 문자를 처리하는 과정인지를 boolean데이터로 가지고 있는 속성인데 ing로 끝나고 있으므로 만약 속성의 값이 true이면, 문자가 처리되고 있는 중이다.


--> 문자를 처리하고 있는 과정의 동작은 필요없으므로 첫 번째로 발생하는 이벤트의 동작은 제거한다.
위처럼 && 로 조건문을 추가하면 출력이 한 번만 나온다.

Focus & Form Events

  • focus : 요소가 포커스를 얻었을 때
  • blur : 요소가 포커스를 잃었을 때
  • input : 값이 변경되었을 때
  • change : 상태가 변경되었을 때
  • submit : 제출 버튼을 선택했을 때
  • reset : 리셋 버튼을 선택했을 때!
    업로드중..

form 요소에서는 submit 이벤트가 발생하게 되면 페이지를 새로고침 하는 것이 기본동작이다. 그러나 우리가 event.preventDefault() 를 사용해서 새로고침이 않도록 만든 후 뒤쪽에서 필요한 내용을 처리할 수 있다.

커스텀 이벤트와 디스패치

const child1 = document.querySelector('.child::nth-child(1)')
const child2 = document.querySelector('.child::nth-child(2)')

child1.addEventListener('click', event => {
    //강제로 이벤트 발생!
    child2.dispatchEvent(new Event('click!'))
    child2.dispatchEvent(new Event('wheel!'))
    child2.dispatchEvent(new Event('keydown!'))
})
child2.addEventListener('click', event => {
    console.log('Child2 Click!')
})
child2.addEventListener('wheel', event => {
    console.log('Child2 Wheel!')
})
child2.addEventListener('keydown', event => {
    console.log('Child2 Keydown!')
})


==> 해당하는 요소의 addEventListner를 통해 적용되어 있는 실제 해당 이벤틀르 화면에서 클릭하거나 휠을 움직이거나 키를 누르지 않고도 dispatchEvent 메서드로 강제로 실행을 할 수있다. 이때 인수는 new라는 키워드로 시작하는 이벤트의 생성자 함수로 해당 이벤트의 이름을 넣어 인수로 넣어준다. => 이벤트의 디스패치

커스텀 이벤트

const child1 = document.querySelector('.child::nth-child(1)')
const child2 = document.querySelector('.child::nth-child(2)')

child1.addEventListener('hello-world', event => {
    console.log('커스텀 이벤트 발생!')
    console.log(event.detail)
})

child2.addEventListener('click', () => {
    child1.dispatchEvent(new Event('hello-world!'))
})

=> js에 존재하지 않는 커스텀한 이벤트의 내용을 작성하고 dispatchEvent라는 메서드를 통해서 실행할 수 있다.

자세하게 >>

child2.addEventListener('click', () => {
    child1.dispatchEvent(new CustomEvent('hello-world!', {
        detail : 123
    }))
})

=> 이벤트에 detail 속성에서 숫자 데이터 123이 출력된다. js에 존재하지 않는 커스텀 이벤트를 만들어서 언제든디 이벤트 생성자 함수로 실행할 수 있는데, 이때 어떠한 데이터를 같이 전달하고 싶다면 두번째 인수로 객체 데이터를 추가하고 detail속성에다가 원하는 js데이터를 넣을 수 있는데,이 데이터는 event클래스에서는 동작하지 않기 떄문데 CustomEvent 클래스를 생성자 함수로 호출 했을 때만, 데이터가 해당하는 커스텀 이벤트의 이벤트 객체에서 detail 속성으로 조회가능

detail속성으로만 데이터를 전달할 수 있기 때문에 detail이름을 그대로 사용해야 하며 이베트 객체에서도 detail 속성의 이름을 그대로 사용해야 한다.

profile
개인 개발 공부, 정리용 🔗

0개의 댓글