See the Pen QWpMONR by unganam (@unganam) on CodePen.
위와 같이 리스트 안에 아이템 리스트가 존재하고 아이템 리스트 안에 또 버튼이 존재하는 html이 있다
여기서 버튼을 눌렸을 때 해당 엘리먼트가 삭제되게끔 이벤트를 등록하려고 한다
li 이벤트 등록의 경우
const $ul = document.querySelector('ul')
const liElems =[...document.querySelectorAll('.item')]
liElems.forEach($li=>$li.addEventListener('click',e=>{
$ul.removeChild(e.target)
}))
페이지 내에 있는 아이템들을 모두 가져와서 배열로 만든 뒤 클릭 이벤트를 주고 클릭 이벤트가 발생하면 부모의 ul에서 해당 엘리먼트를 삭제하는 코드..
처럼 보이지만
다음과 같이 에러가 난다
ul의 자식이 아닌 노드는 삭제할 수가 없다고 하는 에러인데 우리가 이벤트를 준 것은 li태그이지만 실제로 클릭시에 이벤트가 발생하는 엘리먼트는 바로 button이기 때문
button은 ul의 자식이 아니라 삭제를 할 수가 없다
$ul.removeChild(e.target)
를
$ul.removeChild(e.target.parentElement)
// 혹은
$ul.removeChild(e.target.parentNode)
로 바꿔주면 정상적으로 삭제가 된다
하지만 리스트 아이템이 추가된다면 추가되는 만큼 이벤트를 등록해주어야하고 그 갯수가 많아진다면 성능 문제 또한 생기게 된다
ul 이벤트 등록의 경우 (위임, 버블링)
const $ul = document.querySelector('ul')
$ul.addEventListener('click', e=>{
$ul.removeChild(findNode(e.target,'item'))
})
function findNode(node, className){
while (!node.classList.contains(className)){
node = node.parentElement
}
return node
}
함수를 생성하지 않고도 현재 요소에서 가장 가까운 상위요소를 찾는 법이 있다
Element.closest()
const $ul = document.querySelector('ul')
$ul.addEventListener('click', e=>{
$ul.removeChild(e.target.closest('.item'))
})
훨씬 간편해졌다 주의해주어야하는 부분은 노드를 querySelector 형식으로 찾는다는 것 그래서 클래스 명 앞에 .을 붙여주었다
이 코드는 문제가 있는데 선택한 노드가 ul아래엔 있지만 item의 하위요소가 아닐 경우 html문서 밖으로 노드가 나가버려서 에러가 발생한다는 것
const $ul = document.querySelector('ul')
$ul.addEventListener('click', e=>{
const target = e.target.closest('.item')
if(target) {
$ul.removeChild(target)
return
}
})
에러처리를 해주면 된다
See the Pen wvJqpKa by unganam (@unganam) on CodePen.
'JavaScript' 카테고리의 다른 글
modal에 keydown 이벤트 추가하기 (tabindex) (0) | 2021.06.02 |
---|---|
parentElement vs parentNode (0) | 2021.05.25 |
클래스 상속 (0) | 2021.05.23 |
local/session Storage (0) | 2021.05.22 |
fetch API (0) | 2021.05.21 |