jineecode
EVENT 본문
1. id=main-title의 배경색을 파란색으로 바꿀 것임.
<style>
h1 {
background: #fff000;
}
</style>
<body>
<body>
<h1 id="main-title">event</h1>
<ul class="ilbuni-mom">
<li class="ilbuni">
<img src="#" />
<a class="link-google" href="http:google.com">google</a>
</li>
<li class="ilbuni">
<img src="#" />
</li>
<li class="ilbuni">
<img src="#" />
</li>
</ul>
<button class="btn">클릭하세요</button>
<script>
//버튼을 클릭하면 바꾼다 그러면 js로 버튼을 가져와야함
var btn = document.querySelector('.btn')
console.log(btn)
</script>
</body>
event는 어떤 사건이며, 버튼을 클릭하면 이벤트가 발생하며 어떤 동작이 일어남.
2. 버튼을 클릭하면 바꿔야하므로 일단 js로 버튼을 가져와야 함.
<script>
var btn = document.querySelector('.btn')
console.log(btn)
</script>
결과 : <button class="btn">클릭하세요</button>
3. 버튼을 클릭하면 이벤트 배경색을 파란색으로 바꾼다는 것은 동작을 수행한다는 것이며 어떤 기능임. 즉 함수를 만들어야 함
미리 함수를 만들어 놨다가 버튼을 누르면 호출시키도록 코드를 짜야함.
바꿀 부분이 id=main-title 이므로, mainTitle도 가져옴.
<script>
var btn = document.querySelector('.btn')
var mainTitle = document.querySelector('#main-title');
function btnClickHandler() {
}
4.배경색을 바꾼다는 것은 css를 바꾼다는 것.
background : blue 로 해서 css를 추가해서 그 클래스를 넣어도 되고,
js에서 직접 css를 조작할 수도 있음.
js에서 css를 조작할 때 style이라는 객체가 관장함.
<script>
var btn = document.querySelector('.btn')
var mainTitle = document.querySelector('#main-title');
function btnClickHandler() {
mainTitle.style.background = 'dodgerblue';
}
</script>
5.이제 버튼과 함수를 연결시키자.
btn.addEventListener('click',btnClickHandler);
결과
물론 on~ 을 써도 같은 결과가 나온다
btn.onclick = btnClickHandler;
1. 기본 메뉴 만들기: 여러개 중 1개만 활성화 하기
.menu-active {
background: orange;
}
우리가 클릭하게 될 때 css에 이 클래스를 설정해, 그 아이만 오렌지색으로 바뀌게 하기.
<h1 id="main-title">event</h1>
<nav class="menu">
<a href="#" class="menu-link" data-menu="1">menu 1</a>
<a href="#" class="menu-link menu-active" data-menu="2">menu 2</a>
<a href="#" class="menu-link" data-menu="3">menu 3</a>
</nav>
menu2를 클릭했을 때 위와 같이menu-active 클래스가 들어가도록 만드는 게 목적.
2. menu-link들을 js로 가져온다.
<body>
<h1 id="main-title">event</h1>
<nav class="menu">
<a href="#" class="menu-link" data-menu="1">menu 1</a>
<a href="#" class="menu-link" data-menu="2">menu 2</a>
<a href="#" class="menu-link" data-menu="3">menu 3</a>
</nav>
<script>
var menulinks = document.querySelectorAll('.menu-link');
</script>
</body>
3. 3개 모두에게 클릭을 걸어줘야 함. 반복문 사용.
<script>
var menuLinks = document.querySelectorAll(".menu-link");
function clickMenuHandler() {
console.log("click");
}
for (var i = 0; i < menuLinks.length; i++) {
menuLinks[i].addEventListener("click", clickMenuHandler);
}
</script>
확인하면 "click"이 콘솔창에 찍힌다. (잘 작동함)
4. 이제 클릭하면 색이 들어오게 해보자
<script>
var menuLinks = document.querySelectorAll(".menu-link");
function clickMenuHandler() {
this.classList.add("menu-active");
}
for (var i = 0; i < menuLinks.length; i++) {
menuLinks[i].addEventListener("click", clickMenuHandler);
}
</script>
this.classList.add("menu-active");
this를 써서 내가 클릭하는 '요소'에 클래스 'menu-active'를 넣어 색이 들어오게 한다.
this가 가리키는 대상, addEventListener를 호출한 객체 menuLinks[i] 이다.
이 코드의 문제는 다른 것을 클릭했을 때 처음에 클릭한 것의 색이 원래대로 돌아오지 않는다는 점에 있다.
5. 위의 문제를 해결할 수 있는 방법은 여러가지이다.
오렌지색 menu를 다시 파랗게 돌리는 것도 클릭 이벤트이다.
그러므로,
function clickMenuHandler()
함수에 같이 넣어주면 동작하겠다.
5-1 전체를 없애고 다시 오렌지로 바꾼다.
<script>
var menuLinks = document.querySelectorAll(".menu-link");
function clickMenuHandler() {
for (var i = 0; i < menuLinks.length; i++) {
menuLinks[i].classList.remove("menu-active");
}
this.classList.add("menu-active");
}
for (var i = 0; i < menuLinks.length; i++) {
menuLinks[i].addEventListener("click", clickMenuHandler);
}
</script>
menu.classList.remove("menu-active")
'menu-active' class를 모두 지워주고, 필요한 것에 오렌지로 바꾼다.
이 코드의 문제는 우리는 간단한 동작이 필요한데 for문을 돌아야하는 비효율적인 코드이다.
5-2 menu-active를 찾아서 지운다.
<script>
var menuLinks = document.querySelectorAll(".menu-link");
function clickMenuHandler() {
var activeMenu = document.querySelector(".menu-active");
activeMenu.classList.remove("menu-active");
this.classList.add("menu-active");
}
for (var i = 0; i < menuLinks.length; i++) {
menuLinks[i].addEventListener("click", clickMenuHandler);
}
</script>
이 코드에 에러(Uncaught TypeError: Cannot read property 'classList' of null
at HTMLAnchorElement.clickMenuHandler)가 뜨는 이유:
처음에는 당연히 menu-active가 들어있는 class가 없다 (클릭 이벤트가 전혀 발생되지 않음)
조건문을 사용해주어야 함.
<script>
var menuLinks = document.querySelectorAll(".menu-link");
function clickMenuHandler() {
var activeMenu = document.querySelector(".menu-active");
if (activeMenu) {
activeMenu.classList.remove("menu-active");
}
this.classList.add("menu-active");
}
for (var i = 0; i < menuLinks.length; i++) {
menuLinks[i].addEventListener("click", clickMenuHandler);
}
</script>
변수명 activeMenu가 true면 menu-active를 제거하고,
false면 menu-active를 추가해주세요.
이 코드의 단점 역시 속도 문제가 있다.
DOM 자체가 문서를 모두 뒤져야 하기 때문임. (연산 처리)
queryselector은 DOM을 써야하기 때문에 또 범용성이 없다.
5-3. 전역변수를 하나 만드는 방법.
<script>
var currentMenu;
var menuLinks = document.querySelectorAll(".menu-link");
function clickMenuHandler() {
if (currentMenu) {
currentMenu.classList.remove("menu-active");
}
this.classList.add("menu-active");
currentMenu = this;
}
for (var i = 0; i < menuLinks.length; i++) {
menuLinks[i].addEventListener("click", clickMenuHandler);
}
</script>
전역변수 하나를 만든다. (var currentMenu;)
이것은 현재 활성화된 메뉴를 담을 변수 (기억공간).
클릭했을 때 그 값을 currentMenu 변수에 담아놨다가 담은 변수를 classList.remove 하여 비활성화 해주고 클릭한 this를 활성화한다
이렇게 하면 모든 문서를 뒤져볼 필요없이 currentMenu만 찾아서 처리해주면 된다.
이 코드의 단점은 for 문이 있기 때문에 연산의 효율이 떨어진다.
또한 addEventListener이 많을수록 성능 저하가 된다.
이를 해결하는 방법은 이벤트 위임이 있다.
5-4. 이벤트 위임.
menu-link의 부모, menu에게 이벤트를 시킨다.
<style>
.btn {
font-size: 2rem;
}
.menu {
display: flex;
}
.menu-link {
margin: 0.5em;
padding: 0.5em;
color: #fff;
text-decoration: none;
background: dodgerblue;
list-style: none;
}
.menu-active {
background: orange;
}
.menu {
background: yellowgreen;
}
</style>
</head>
<body>
<h1 id="main-title">event</h1>
<nav class="menu">
<a href="#" class="menu-link" data-menu="1">menu 1</a>
<a href="#" class="menu-link" data-menu="2">menu 2</a>
<a href="#" class="menu-link" data-menu="3">menu 3</a>
</nav>
<script>
var menu = document.querySelector(".menu");
function clickHandler() {
console.log(this);
}
menu.addEventListener("click", clickHandler);
</script>
var menu = document.querySelector(".menu");
변수 menu를 가져온다 (DOM)
menu.addEventListener("click", clickHandler);
부모인 menu에게 click이벤트를 준다.
이때, 매개변수 두번째 자리에 clickHandler 라는 함수를 만든다.
function clickHandler() {
console.log(this);
}
콘솔을 찍어본다. (클릭이벤트 잘 되는지 실행)
잘 가져왔음.
여기서 this는 addEventListener의 menu가 찍힘
5-5.
<script>
var menu = document.querySelector(".menu");
function clickHandler(e) {
console.log(e);
}
menu.addEventListener("click", clickHandler);
</script>
clickHandler 앞에 e 는 뭘까?
clickHandler 함수가 addEventListener로서 실행이 되면, 첫번째 자리에 event 객체라는 특별한 객체가 들어옴. 그것이 바로 매개변수 e 임.
이것을 찍어보면,
수많은 클릭 이벤트 객체가 나열되어서 들어옴.
이 수많은 이벤트 객체 중 하나를 찍어보자
<script>
var menu = document.querySelector(".menu");
function clickHandler(e) {
console.log(e.currentTarget);
}
menu.addEventListener("click", clickHandler);
</script>
이것은 this와 같은 결과이다.
<script>
var menu = document.querySelector(".menu");
function clickHandler(e) {
console.log(this == e.currentTarget);
}
menu.addEventListener("click", clickHandler);
</script>
true 가 나옴
<script>
var menu = document.querySelector(".menu");
function clickHandler(e) {
console.log(e.target);
}
menu.addEventListener("click", clickHandler);
</script>
결과:
부모를 가리키지 않는다.
진짜 내가 누른 타겟을 가져옴.
이것이 바로 이벤트 위임이다.
반복문을 쓰지 않은 가장 이상적인 코딩이다.
<script>
var currentMenu;
var menu = document.querySelector(".menu");
function clickHandler(e) {
if (currentMenu) {
currentMenu.classList.remove("menu-active");
}
e.target.classList.add("menu-active");
currentMenu = e.target;
}
menu.addEventListener("click", clickHandler);
</script>
리팩토링
<script>
var currentMenu;
var menu = document.querySelector(".menu");
function activate(elem){
elem.classList.add("menu-active");
currentMenu = elem;
}
function inactivate(elem){
currentMenu.classList.remove("menu-active");
}
function clickHandler(e) {
if (currentMenu) {
inactivate(currentMenu);
}
activate(e.target);
}
menu.addEventListener("click", clickHandler);
</script>
이 코드의 장점은 따로 activate를 호출해놨기 때문에
사이트에 들어갔을 때부터 nav를 열어둘 수 있다.
<script>
var currentMenu;
var menu = document.querySelector(".menu");
function activate(elem){
elem.classList.add("menu-active");
currentMenu = elem;
}
function inactivate(elem){
currentMenu.classList.remove("menu-active");
}
function clickHandler(e) {
if (currentMenu) {
inactivate(currentMenu);
}
activate(e.target);
}
menu.addEventListener("click", clickHandler);
activate(document.querySelectorAll('.menu-link')[0]);
</script>
'JS' 카테고리의 다른 글
지역 선택 JS로 제어하기 (2) | 2021.02.26 |
---|---|
이벤트 위임 (0) | 2021.02.25 |
깨알 기초 지식 모음 (0) | 2021.02.14 |
끝말잇기 만들기 (0) | 2020.12.08 |
DOM 스크립트 (0) | 2020.11.25 |