Skip to content

Latest commit

 

History

History
257 lines (197 loc) · 10.2 KB

week07-10-16-18.md

File metadata and controls

257 lines (197 loc) · 10.2 KB

10-16-18


오늘 수업 교재

이벤트 객체

  1. e.target - 실제 이벤트를 일으킨 요소

이벤트를 실제로 일으킨 요소와 이벤트리스너가 등록되어있는 요소는 같지 않을 수 있다.

예시

document.querySelector(".outer").addEventListener("click", e => {
  alert("outer가 클릭되었습니다.");

  // 이벤트 리스너가 직접 실행된 요소 객체. 여기서는 '.button'.
  alert("target의 class:" + e.target.getAttribute("class"));
  // 현재 이벤트 전파 과정 중에 이벤트 리스너가 등록되어있는 '그 요소 객체'가 들어있다. 여기서는 ''.outer'.
  alert("currentTarget의 class:" + e.currentTarget.getAttribute("class"));
});

// document.querySelector('.inner').addEventListener('click', e => {
//   alert('inner가 클릭되었습니다.');
//   alert('target의 class:' + e.target.getAttribute('class'));
//   alert('currentTarget의 class:' + e.currentTarget.getAttribute('class'));
// });

// document.querySelector('button').addEventListener('click', e => {
//   alert('버튼이 클릭되었습니다.');

//   alert('target의 class:' + e.target.getAttribute('class'));
//   alert('currentTarget의 class:' + e.currentTarget.getAttribute('class'));
// });

// document.querySelector('.outer2').addEventListener('click', e => {
//   alert('outer2가 클릭되었습니다.');
// });

todo-list 예제에서 변수명 사용하지 않고 e.target, e.currentTarget을 사용해서 쓰기(클래스를 사용하지 못해 변수명을 작성하지 못할 경우가 있다).

 // 변수명을 사용하지 않고도 e.target과 e.currentTarget 사용해서 표현하기
    e.target.parentElement.parentElement.removeChild(e.target.parentElement)
    // todoListEl.removeChild(todoItemEl)
  })

document.querySelectorAll 사용하면 node.list 객체가 반환된다!!! 이는 for each 라는 메소드를 자기 자신이 가지고 있어서 사용할 수 있다(배열이 아니더라도 사용이 가능)

// for each 다음 divEl이 변수명을 지어준 것
document.querySelectorAll("div").forEach(divEl => {
  divEl.addEventListener("click", e => {
    // target과 달리 currentTarget 사용 시에는 버블링 단계 때문에 이 후에 버블링 단계 효과를 받는 모든 div 요소들의 배경색도 바꿀 것이다!!!
    // target은 이벤트리스너가 어디에 등록되어있던 상관없이 정말 e.target이 설정되어있는 요소만 가리키기 때문에 그 요소의 배경색만 바꾼다.
    e.currentTarget.style.backgroundColor = "green";
  });
});

버블링이 일어나는 이벤트도 있고, 일어나지 않는 이벤트도 있음 (submit, focus, blur, change 등 form 과 관련된 이벤트들은 특정 타입의 요소를 위해서 존재하기 때문에 캡쳐링이나 버블링이 일어나지 않는다)

폼 이벤트

e.target.value - 입력된 값을 반환한다.

input 태그에 change 이벤트 리스너는 사용하지 않는다. 그래서 input 이벤트 리스너를 사용하는 것. change 이벤트 리스너는 사용자가 직접 사용을 해야하는 경우에 많이 사용된다.

타입이 text 일 때에는 input 이벤트리스너를 사용하고, 그 외의 타입(checkbox) 일 때에는 change 이벤트리스너를 사용하면 된다.

// 이 경우에는 'div'요소도 입력가능하게 만든 것으로, 인풋 이벤트리스너를 사용한다.
document.querySelector(".contenteditable").addEventListener("in ut", e => {
  console.log("contenteditable input");
});
  • 폼 이벤트 예제(submit)
    • 전송 버튼을 누르거나 혹은 엔터키를 치거나 해서 전송을 시킬 수 있다 - 이는 브라우저의 내장 기능.
    • form 안에 button 을 지정해주고 사용하면(아무 attribute 없이) 전송이 정상적으로 동작하는데, 이는 브라우저의 내장 기능이다(이는 아무 속성값이 지정되지 않았을 시에 submit 이 기본값이기 때문).

요즘 form이 제공하는 전송 기능을 잘 사용하지 않음에도(자바스크립트로 처리하기 때문), 이 form 이 제공하는 편리한 내부기능을 사용하기 위해 form 태그가 많이 사용된다.

e.target.elements을 사용한 예 - 자바스크립트를 통한 아이디, 패스워드 검증 시에

document.querySelector("form").addEventListener("submit", e => {
  // form이 타겟이고 그것의 자식 요소들을 가리킨다. 물론 form 요소를 대상으로 선언했기 때문에, 이 안의 요소들에게만 타겟이 지정된다.
  const elements = e.target.elements;
  // elements.id는  <input type="text" name="id" required>에 있는 id를 가리킨다.
  if (!elements.id.value || !elements.password.value) {
    e.preventDefault();
    alert("아이디와 비밀번호를 모두 입력하셔야 합니다.");
  }
});

form 태그를 사용할 때 이벤트리스너 등록 시에만 밑에와 같이 이벤트리스너의 첫 인수로 submit 사용할 수 있다(무엇이 전송될 때 발생하는 것)

todoFormEl.addEventListener("submit", e => {
  // 전송되는 것 막기 위해
  e.preventDefault();

  addTodo(e.target.elements.todo.value); // input객체에 이름이 todo인 것들을 모두 지정
});

마우스 이벤트

마우스 클릭, 더블 클릭

boxEl.addEventListener("dblclick", e => {
  alert("더블 클릭");
});

마우스 무브

모든 요소 위에서 실행되는 마우스무브 - document는 문서 전체를 가리킨다.
document.addEventListener('mousemove', e => {
  console.log('포인터 이동', e.clientX, e.clientY)
})

마우스 오버, 아웃

boxEl.addEventListener('mouseover', e => {
  console.log('포인터 올라감')
})

boxEl.addEventListener('mouseout', e => {
  console.log('포인터 벗어남')
})

스크립트로도 마우스 호버 기능을 할 수 있다. 하지만 이는 최대한 CSS에서 구현할 수 있다면 하는 곳이 옳다.

boxEl.addEventListener('mouseover', e => {
  console.log('포인터 올라감')
  e.target.style.backgroundColor ='red'
})

boxEl.addEventListener('mouseout', e => {
  console.log('포인터 벗어남')
  e.target.style.backgroundColor = 'green'
  // boxEl.style.backgroundColor... 나는 이렇게 작성했었다. 하지만 `e.target`을 사용하면 안의 요소를 선택 가능...

})

그렇기 때문에 script에서는 단지 클래스의 추가를 해주거나 한 뒤에 CSS를 선택시키면 된다

boxEl.addEventListener('mouseover', e => {
  console.log('포인터 올라감')
  e.target.classList.add('hover')
})

boxEl.addEventListener('mouseout', e => {
  console.log('포인터 벗어남')
  e.target.classList.remove('hover')
})

작성 후,

.box.hover{
  background-color:red;
}

이런 식으로 css에 설정해주면 된다.

과제!!! mouseenter, mouseleave가 mouseover와 mouseout의 차이가 무엇인지를 찾아보자.

  • mouseenter는 마우스가 만약에 이것이 설정된 요소 위에 올려졌을 때만 한 번 실행이되고, 다시 마우스 포인터가 그 요소를 나가기 전에는 상태의 변화가 없다. 즉 마우스엔터가 설정된 요소에 올라갔을 그 즉시에만 이벤트가 실행이 된다. mouseleave도 결국 그 설정된 요소 밖으로 마우스 포인터가 움직였을 시에 적용된다. 이 설정된 요소 안의 자식요소에게는 영향을 끼치지 않는다.

  • mouseover는 이벤트가 실행되는 조건이 마우스가 이것이 설정된 요소 위에 올라갔을 때와, 그 요소 내의 자식 요소들에게도 해당이 된다. mouseout도 설정이 된 해당 요소에서 벗어나거나 그 자식요소 외의 다른 영역을(해당요소를 가리키더라도) 가리킬 때 실행이 된다.

마우스 드래그 앤드 드롭 실습... 생각하지 못했다.. 후..

// 마우스가 클릭 되었는지 안되었는지 그 상태를 확인해주는 변수 선언
 let dragging = false
 
 boxEl.addEventListener('mousedown', e => {
   dragging = true
 })

boxEl.addEventListener('mouseup', e => {
  dragging = false
})

// document - 문서 전체 - 에 대한 적용을 해주어야 원하는 효과가 나온다(마우스가 확 벗어나더라도).
document.addEventListener('mousemove', e => {
  if (dragging) {  
  // 이 좌표는 박스의 왼쪽 끝(좌측 상단)을 뜻하기 때문에 마우스가 움직일 때 마우스 포인터가 계속 상자의 좌측상단으로 맞추어지게 된다.
  boxEl.style.top = `${e.clientY}px`
  boxEl.style.left = `${e.clientX}px`
  }
})

el.getBoundingClientRect()를 사용하여 자연스럽게 드래그 시켜보자...

  • const rect = boxEl.getBoundingClientRect()로 설정을 했다 치자.
  • rect.left 가 x 좌표, rect.top 이 y 좌표, 마우스 포인터의 좌표는 e.clientX, e.clientY.
  • e.clientX - rect.left를 뺀 값, e.clinetY - rect.top을 뺀 값을 구한 뒤 마우스를 땔 때 값을 대입하는 식으로 생각을 하자...

keypress... etc...

// 인풋은 인풋태그에만 사용이 가능하지만 - 키업, 키다운, 키프레스 등은 어디에나 사용 가능하다(언어 때문에 문제가 생길 수도 있다.)
document.querySelector('.todo-input').addEventListener('keypress', e => {
  console.log('keypress')
  console.log('key:', e.key)
})

키보드를 눌러도 스크롤이 되지않게 할 때:

document.querySelector('.todo-input').addEventListener('keydown', e => {
  console.log('키가 눌렸을 때')
  console.log('key:', e.key)
  e.preventDefault()
})

클로저는 무엇!? : 바깥 스코프에 있는 변수를 가져다 사용하는 함수와, 변수가 저장되는 저장소를 클로저(closure)라고 부릅니다.


수업 후 질문 중

<!-- CSS 선택자  -->

 /* 밑과 같이 작성된 CSS 선택자는 option클래스와 abc 클래스 모두가 적용된 html요소를 가리킨다. */
.option.abc {
  border: 1px solid black;
  width: 30px;
  height: 30px;
}

/* 밑과 같이 작성된 CSS 선택자는 option을 클래스로 가지고 있는 html요소의 자식 요소 중에 .abc라는 클래스를 가지고 있는 요소를 가리킨다. */
.option .abc {
  border: 1px solid black;
  width: 30px;
  height: 30px;
  
}