상세 컨텐츠

본문 제목

이벤트 동적 바인딩 당신만 몰라용!!

자바스크립트

by e7e 2023. 11. 23. 19:42

본문

당황스럽당. 당연하게 받아들여질 수  있는 개념이, 현학적 용어와  배려없는 코드에 묻혀서

어렵고 대단하고 학문적인 것으로 받아들여지는 것이........

내면보단 외모가, 내용보단 형식이,  실체보다는 브랜드가, 의도파악보단  편견적 결론이... 

 

브라우져 자바스크립트(jQuery에서동)에서 의식적 무의식적으로 많이 사용되지만,

개념 이해없이 마구 사용되는 이벤트 동적바인딩에 대해  쪼메 이야기 해보장.    

 

먼저 아래 코드를 눈으로 SSG(쓱) Top->Down으로 그냥 읽자.

단순 클릭 이벤트 등록이라 버튼 누르면 alert가 실행 될 꺼이당.(오켕?)

 

이벤트동적바인딩1.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>E7E 만만세</title>
</head>

<body>
    <div id="disp">
        <button id="e7eBtn">E7E 눌렁</button>
    </div>
    <script>
        const disp = document.querySelector("#disp");
        const e7eBtn = document.querySelector("#e7eBtn");
        //이벤트 등록
        e7eBtn.addEventListener("click", () => {
            alert("안농! 난 E7E얌");
        })
    </script>
</body>

</html>

위 소스에 아래 그림처럼 2번째 버튼을 하나 추가 할 꺼당.

2번째 버튼을 누르면   첫번째 버튼을 지우고, 똑같이 생긴, 심지어 id도 같은 버튼

사용자가 느낄 수 없는 속도로(F12를 누른 개발자는 Elements탭의 변화가 보인당)

다시 그 자리에 넣는 함수를 추가 하면

 

대략 아래와 같은 소스가 될 것이다. 눈만으로는 부담스럽다면,

복사/붙여넣기로  비주얼 스튜디어 코드로 실행/확인 준비하장

[상황을 심플하게 하기 위해, 2번째 버튼은 오직 한번만 누르는 거스로 가정하였당]

 

이벤트동적바인딩2.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>E7E 만만세</title>
    <style>
        button {
            width: 200px;
            font-size: 2em;
        }
    </style>
</head>

<body>
    <div id="disp">
        <button id="e7eBtn">E7E 눌렁</button>
    </div>
    <br>
    <button onclick="fRmAdd()">위 버튼 삭제후 똑같이 다시넣깅</button>
    <script>
        const disp = document.querySelector("#disp");
        let e7eBtn = document.querySelector("#e7eBtn");
        //이벤트 등록
        e7eBtn.addEventListener("click", () => {
            alert("안농! 난 E7E얌");
        });

        const fRmAdd = () => {
            // e7eBtn 버튼 삭제
            disp.removeChild(e7eBtn);

            // 같은 정보를 가진 버튼태그 새로 생성
            let newBtn = document.createElement("button");
            newBtn.setAttribute("id", "e7eBtn");
            newBtn.innerHTML = "E7E 눌렁";
            // 지운자리에 넣기
            disp.appendChild(newBtn);

        }
    </script>
</body>

</html>

 

실행 테스트!

1. 실행 후 첫번째 버튼을 누르면 alert 등장
2. 두번째 버튼 누름(기존 첫번째 버튼을 지우고, 똑같이 생긴 애를  추가하는 눈속임
3. 첫번째 버튼을  다시 누르면 엥! alert 안 등장!  

 

왱? id도 똑같고, elemement탭에서 보면 html소스도 정확히 똑같은뎅!! ~~

모양은 똑같지만, 서로 다른 버튼임을 인지하는 것이 중요하당.

지난번에 산 페라리를 버리고, 똑같은 새 페라리를 다시 산 거당. (실체가 다르당!)

이전 버튼에 등록한(바인딩) 클릭 이벤트는, 새로 추가한 버튼에는 없당! (오케?)

 

그럼 새로 추가된(동적생성) 버튼에 이벤트가 등록 되도록 수정해 보장.

그저 새로 만든 버튼에 이벤트를 다시 등록(바인딩)하면 된당.

아래와 같은 소스가 될 꺼이당. (오켕?)

 

이벤트동적바인딩3.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>E7E 만만세</title>
    <style>
        button {
            width: 200px;
            font-size: 2em;
        }
    </style>
</head>

<body>
    <div id="disp">
        <button id="e7eBtn">E7E 눌렁</button>
    </div>
    <br>
    <button onclick="fRmAdd()">위 버튼 삭제후 똑같이 다시넣깅</button>
    <script>
        const disp = document.querySelector("#disp");
        let e7eBtn = document.querySelector("#e7eBtn");
        //이벤트 등록
        e7eBtn.addEventListener("click", () => {
            alert("안농! 난 E7E얌");
        });

        // 버튼 삭제 새로 추가 함수
        const fRmAdd = () => {
            // e7eBtn 버튼 삭제
            disp.removeChild(e7eBtn);

            // 같은 정보를 가진 버튼태그 새로 생성
            let newBtn = document.createElement("button");
            newBtn.setAttribute("id", "e7eBtn");
            newBtn.innerHTML = "E7E 눌렁";
            // 지운자리에 넣기
            disp.appendChild(newBtn);

            /** 새로 만들어진 버튼에 이벤트 등록
                동적 이벤트 바인딩! , removeEventListener 있다는 사실
             **/
            newBtn.addEventListener("click", () => {
                alert("안농! 난 E7E얌");
            });

        }
    </script>
</body>

</html>

 

이제 다시 첫번째 -> 두번째-> 첫번째 버튼을 눌러도 alert가 뜬당!

(이거이 이벤트 동적바인딩이란 거시당. 동적생성되는 요소에 동적으로 이벤트 추강

무조건 이해되었당!!!! (당신만 몰랐당. 당신에게 IT 천재자질이 있다는 사실을...)


요기서 쪼메만  더 멋져 보이겡 한발짝(마니 가면 서로 피곤함)만 더 나아가 보장!

자바스크립트에선 event를 관리하는 event객체가 target이란 속성이 있어서

누구로부터 이벤트가 발생했는지를 알 수 있당.( event.target  과 event.currentTarget 비교)

 

event.target 을이용하는 여기서의 스토리는 이렇당.

1. 문서(document)의 어디에서든 클릭이벤트가 발생하면,

2. 문서에서 id가 e7eBtn인 element(요소, 태그객체)를 서치하고, 있다면

3. 그것과 event.target(이벤트를 발생시킨 요소)을 비교하여 같은 거라면

4. 찾은 것에 새로 이벤트를 등록해 주고,  이벤트에 등록된 함수가 실행되어야 하닝

5. 강제로 이벤트를 발생시킨다는 머 그런 아주 쉽고 간략한 야그당.

 

스토리를 반영하여 소스를 수정하면 대략 아래와 비스무리 할거당.

[잠시 시간 내어, 정적 이벤트 등록 주석처리 와 새로 추가된 부분을 스토리랑 비교하장]

이벤트동적바인딩4.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>E7E 만만세</title>
    <style>
        button {
            width: 200px;
            font-size: 2em;
        }
    </style>
</head>

<body>
    <div id="disp">
        <button id="e7eBtn">E7E 눌렁</button>
    </div>
    <br>
    <button onclick="fRmAdd()">위 버튼 삭제후 똑같이 다시넣깅</button>
    <script>
        const disp = document.querySelector("#disp");
        let e7eBtn = document.querySelector("#e7eBtn");

        /* 이벤트 등록
        e7eBtn.addEventListener("click", () => {
            alert("안농! 난 E7E얌");
        });
        */

        // 버튼 삭제 새로 추가 함수
        const fRmAdd = () => {
            // e7eBtn 버튼 삭제
            disp.removeChild(e7eBtn);

            // 같은 정보를 가진 버튼태그 새로 생성
            let newBtn = document.createElement("button");
            newBtn.setAttribute("id", "e7eBtn");
            newBtn.innerHTML = "E7E 눌렁";
            // 지운자리에 넣기
            disp.appendChild(newBtn);

        }


        // 이벤트 동적 바인딩, jQuery방식 구현
        document.addEventListener("click", () => {
            let e7eBtn = document.querySelector("#e7eBtn");
            console.log(event.target == e7eBtn);  // 디버깅용
            if (e7eBtn == event.target) {
                e7eBtn.onclick = () => {
                    event.stopPropagation();  //지금은 요거이 아주 필요 & 중요
                    alert("안농! 난 E7E얌");
                }
                e7eBtn.click();
            }
        });


    </script>
</body>

</html>

실행해 보면 이전과 같은 결과가 나옴을 확인 할 수 있당.

코드 상에서 이해 안되는 부분이 있다면, 항상 console.log를 이용하여

흐름이나, 그거시 누굴 가리키는 지 꼬옥 확인하장.

내가 아는 자바스크립트를 잘 하는 절대 원칙은 오직 하낭,

"console.log를 마구 난발 후에, 개념 정리 하장" 이당.


위 내용까지 이해되었다면, 자바스크립트로 jQuery의 동적바인딩을 실제로

자신만의 소스로 구현할 수 있게 되는 데,  여기선 거기까지 가면 소스 기럭지가 너무나동

길어지닝 간략히 함수형태로 흉네  한번 내어 보장.

 

아래는 아직 merong이라는 클래스를 가진 버튼들이 없는 상황에서,  미리

미래에 merong이라는 클래스를 가진 버튼들이 추가되었을 때, 해당 버튼들에  클

릭이벤트가 발생하면 alert창이 뜨도록 하는 함수(이름 fDynamicEvt)를 추가한 소스당.

시간을 내서 기피되지 않을만큼만 기피있게 소스를 분석하는 시간을 갖도록 하장!

이벤트동적바인딩결론.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>E7E 만만세</title>
    <style>
        button {
            width: 200px;
            font-size: 2em;
            display: block;
        }
    </style>
</head>

<body>
    <div id="disp">
        <button id="e7eBtn">E7E 눌렁</button>
    </div>
    <br>
    <button onclick="fRmAdd()">위 버튼 삭제후 똑같이 다시넣깅</button>
    <button onclick="fAddMerong()">.merong 버튼 테스트롱 여러개넣깅</button>
    <script>
        /////////////////*  전역변수 선언부     *//////////////    
        const disp = document.querySelector("#disp");
        let e7eBtn = document.querySelector("#e7eBtn");

        /////////////////*  전역함수 선언     *//////////////    
        // 버튼 삭제 새로 추가 함수
        const fRmAdd = () => {
            // e7eBtn 버튼 삭제
            disp.removeChild(e7eBtn);

            // 같은 정보를 가진 버튼태그 새로 생성
            let newBtn = document.createElement("button");
            newBtn.setAttribute("id", "e7eBtn");
            newBtn.innerHTML = "E7E 눌렁";
            // 지운자리에 넣기
            disp.appendChild(newBtn);

        }

        // .merong class를 가진 임의로 여러개 맹글어넣깅
        const fAddMerong = () => {
            let ranNum = Math.ceil(Math.random() * 3) + 2;  // 2~5
            let ranBtn = null;
            for (let i = 1; i <= ranNum; i++) {
                ranBtn = document.createElement("button");
                ranBtn.setAttribute("class", "merong");
                ranBtn.innerHTML = `메롱${i}`;
                ranBtn.style.backgroundColor = "black";
                ranBtn.style.color = "green";
                disp.appendChild(ranBtn);
                //요기서 이벤트 등록은 없음!
            }
        }

        // 동적객체(없던것이 생기는 케이스) 이벤트 등록함수
        const fDynamicEvt = (context, evt, selector) => {
            context.addEventListener(evt, () => {
                // 요 아래 줄이 뽀인또로 Search해서 찾아온다는 것이 뽀인또
                let elemTags = context.querySelectorAll(selector);
                if (elemTags && elemTags.length) {
                    for (let i = 0; i < elemTags.length; i++) {
                        console.log("디버깅3", elemTags[i] == event.target);
                        if (elemTags[i] == event.target) {
                            elemTags[i].onclick = () => {
                                event.stopPropagation();  //지금은 요거이 아주 필요 & 중요
                                alert("안농! 난 E7E얌");
                            }
                            elemTags[i].click();
                        }
                    }
                }
            });
        }

        /////////////////*  이벤트 등록부     *//////////////    
        /* 동적 바인딩으로 필요없어짐!
        e7eBtn.addEventListener("click", () => {
            alert("안농! 난 E7E얌");
        });
        */

        /////////////////*  코드 실행부     *//////////////    
        fDynamicEvt(document, "click", "#e7eBtn");

        // 아직 존재하지 않는 css merong class를 가진 버튼에 이벤트 등록
        // 정확히는 찾아지면 이벤트를 등록
        fDynamicEvt(document, "click", ".merong");

    </script>
</body>

</html>

 

실행해서, .merong 버튼.... 이라고 쓰여진 버튼을 누르면, 아래 그림처럼

2개에서 5개까지 랜덤하게 버튼이 새로 추가되공,

해당 버튼에 모두 클릭이벤트가 등록되는 걸 확인 할 수 있당.(훌륭하당!)

 

만약 스스로 진짜 완벽하게 이해가 되었는지 테스트하고 싶다면 ,

fDynamicEvt 함수의 네번째 매개변수로 콜백(Callback)함수를 받을 수 있도록 

수정해 보는 시간을 가지는 것은 정말로 값진 시간이 될 것이당.(당신은 이미 최고당!)

 

 DOM.on이벤트명 = 함수명  과 DOM.addEventListener("이벤트명", 함수명) 의 차이

event.stopPropagation의 의미가 명확하지 않은 사람은 이번 기회에 명확히 하는 

시간을 가진다면  그 역시 값을 메길 수 없는 보석같이 빛나는 시간이 될 것이당.

 

만약 모르겠다면,  ??가 안 이해되용을 남겨주는 수고를 부탁한당.

 

사실 나의 경우에는 이벤트 동적바인딩이 필요할 때  HTML 문자열에 이벤트를 기술하고

해당 문자열을 innerHTML로 주입시키는 방법을 좋아한당.

(왜? 편하니깡!!! 그리고 그리 있어보이는 게 중요하지 않음도 어느덧 깨달았당)

 


 

유난히도 별이 없던 그 밤!

어차피 잡을 수 없다면, 금수저!

너도 날 잡을 수 없게 만들었당.

 

이제 너도 날 잡을 수 없당.

쌤쌤이당.

 

산다는 건 기쁜 일이당.

샤오미 패드의 가격은 불신의 벽을 뚫고 날 유혹했당. 

지금 난 기대감으로 도착을 기다린당.

산다는 건 그런거당. 아픔에도 기대는 버리지 않는당.

 

그저  머 그런 그런 것들이 줄지어 기다리고

필요하다면 사는 거, 그게 산다는 것이당.

산다는 거 넌 날 잡을 수 없엉!!

산다는 거 그거 기다려진당... 도착까지도...

 

 

https://www.youtube.com/watch?v=GlM6lcFbLSg

 

관련글 더보기