TIL - 37. Event [230905]

송원철·2023년 9월 5일

06_이벤트.html

06_이벤트.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>06_이벤트</title>

    <style>
        #test3 {
            width: 200px;
            height: 200px;
            border: 1px solid black;
            background-color: pink;
            cursor: pointer;
        }

        /* 복습문제 */
        #div1 {
            width: 100px;
            height: 100px;
            border: 1px solid black;


        }
    </style>
</head>
<body>
    <h1>이벤트(Event)</h1>

    <pre>
        이벤트(Event): 동작, 행위
        -> 브라우저에서의 동작, 행위 : click, keyup, keydown, mouseover, drag, change, submit...

        https://www.w3schools.com/jsref/dom_obj_event.asp

        
        이벤트 리스터(Event Listener)
        -> 이벤트가 발생하는 것을 대기하고 있다가 
        이벤트가 발생하는 것이 감지되면 연결된 기능(함수)를 수행하는것

        ex) onclick, onkeyup, onchange, onsubmit ... (on 이벤트명)


        이벤트 핸들러(Event Handler)
        -> 이벤트 리스너에 연결된 기능으로
            이벤트 발생 시 수행하고자 하는 내용을 작성해둔 함수

        <!-- ex ) <button onclick = "readValue()"></button> -->
        <!--           이벤트리스너   이벤트핸들러-->
    </pre>

    <hr>

    <h3>인라인 이벤트 모델</h3>
    <pre>
        요소 내부에 이벤트를 작성하는 방법으로

        on이벤트명 = 함수명()    형태로 작성함. 
    </pre>

    <button onclick="test1(this)">인라인 이벤트 모델 확인</button>

    <hr>

    <h3>고전 이벤트 모델</h3>
    <pre>
        요소가 가지고 있는 이벤트 속성(이벤트 리스너)에 
        이벤트 핸들러를 연결하는 방법으로

        인라인 모델처럼 HTML 요소에 JS 코드를 포함되는 것이 아닌
        script에만 이벤트 관련 코드를 작성할 수 있다.
    </pre>

    <button id="test2-1">고전 이벤트 모델 확인</button>

    <button id="test2-2">고전 이벤트 모델 제거</button>

    <button id="test2-3">고전 이벤트 모델 단점</button>


    <hr>

    <h3>표준 이벤트 모델(addEventListener)</h3>
    <pre>
        - W3C (HTML, CSS, JS 웹표준 지정 단체)에서
        공식적으로 지정한 이벤트 모델(이벤트 동작 지정 방법)

        - 한 요소에 여러 이벤트 핸들러를 설정할 수 있다.
        -> 고전 이벤트 모델 단점 보완
    </pre>

    <div id="test3">클릭하면 크기가 늘어나요!</div>


    <hr>

    <h3>이벤트 복습 문제</h3>
    색상을 영어로 입력한 후 변경 버튼을 클릭하면 #div1 의 배경색이 변경되도록 하시오.

    <div id="div1"></div>

    <input id="input1">

    <button id="changeBtn1">변경</button>


    <hr>

    <h1>HTML 요소 기본 이벤트 제거</h1>
    <h3>a태그 기본 이벤트 제거</h3>
    <a id="moveNaver" href="https://www.naver.com">네이버로 이동</a>



    <script src="js/06_이벤트.js"></script>
</body>
</html>

06_이벤트.js

// 인라인 이벤트 모델 확인하기
function test1(btn) {
    console.log(btn);

    btn.style.backgroundColor = "black";
    btn.style.color = "white";
}


// 고전 이벤트 모델 확인하기

// ** 주의사항 ** 
// 고전/표준 이벤트 모델은 랜더링된 HTML 요소에
// 이벤트에 관련된 동작을 부여하는 코드

// -> 랜더링이 되지 않은 요소에는 관련 동작을 추가할 수 없다!!
//  (문제 원인 : HTML 코드 해석 순서 (위->아래)

// 해결방법 : HTML 요소가 먼저 랜더링 된 후 JS 코드 수행할 수 있도록
//          body 태그 맨 아래 script 태그를 넣는다

document.getElementById("test2-1").onclick = function() {
    // 익명함수(이벤트 핸들러에 많이 사용함)

    alert("고전 이벤트 모델로 출력된 대화상자");
}

// 이벤트 제거
document.getElementById("test2-2").onclick = function() {

    document.getElementById("test2-1").onclick = null;

}


// 고전 이벤트 모델 단점
// -> 한 요소에 동일한 이벤트 리스너(onclick)에 대한
// 다수의 이벤트 핸들러(배경색 변경, 폰트크기 변경)를 작성할 수 없다.
// (마지막으로 해석된 이벤트 핸들러만 적용)

document.getElementById("test2-3").onclick = function(event) {
    // 버튼 색 바꾸기 
    // 방법 1) 요소를 문서에서 찾아서 선택
    //document.getElementById("test2-3").style.backgroundColor = "pink";

    // 방법 2) 매개변수 e 또는 event 활용하기
    // -> 이벤트 핸들러에 e 또는 event를 작성하는 경우
    // 해당 이벤트와 관련된 모든 정보가 담긴 이벤트 객체가 반환된다.
    //console.log(event);

    // event.target : 이벤트가 발생한 요소
    //event.target.style.backgroundColor = "pink";

    // 방법 3) this 활용하기 -> 이벤트가 발생한 요소
    this.style.backgroundColor = "pink";
}

document.getElementById("test2-3").onclick = function() {
    this.style.fontSize = "30px";
}

// 표준 이벤트 모델

/*
    요소.addEventListener("click", function() {})

*/

document.getElementById("test3").addEventListener("click", function() {

    console.log(this.clientWidth); // 현재 요소의 너비(테두리 제외)

    this.style.width = this.clientWidth + 20 + "px";

});

// test3에 이미 click 이벤트에 대한 동작이 존재하는데,
// 중복해서 적용 (고전 이벤트 모델 문제점 해결 확인)
document.getElementById("test3").addEventListener("click", function() {
    
    this.style.height = this.clientHeight + 20 + "px";

});


// 복습 문제
document.getElementById("changeBtn1").addEventListener("click", function() {

    const div1 = document.getElementById("div1");
    const input1 = document.getElementById("input1");

    // input1에 작성된 값 얻어오기
    const bgColor = input1.value;

    // div1 배경색 변경 
    div1.style.backgroundColor = bgColor;

});


// input1에 작성한 값이 변경되었을 때 입력된 값으로 배경색 변경
document.getElementById("input1").addEventListener("change", function() {

    // change 이벤트
    // - test관련 input태그는
    // 입력된 값이 변할 때를 change라고 하지 않고

    // 입력이 완료된후 포커스를 잃거나, 엔터를 입력하는 경우 
    // 입력된 값이 이전값과 다를 경우에 change 이벤트가 발생한걸로 인식.

    console.log("change 이벤트 발생");

    const div1 = document.getElementById("div1");
    const input1 = document.getElementById("input1");

    // input1에 작성된 값 얻어오기
    const bgColor = input1.value;

    // div1 배경색 변경 
    div1.style.backgroundColor = bgColor;

});

// a태그 기본 이벤트 제거 
document.getElementById("moveNaver").addEventListener("click", function(e) {

    // 매개변수 e또는 event == 이벤트 발생 객체 
    // 이벤트와 관련된 정보가 담겨있는 객체

    e.preventDefault(); // HTML 요소가 가지고있는 기본 이벤트를 막음(제거)

});



07_정규표현식.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>07_정규표현식</title>

    <style>
        .area {
            width: 500px;
            min-height: 300px;
            border: 1px solid black;
        }

        .confirm { color: green;}
        .error { color: red;}
    </style>

</head>
<body>
    <h1>정규표현식(Regular Expression)</h1>
    <pre>
        특정한 규칙을 가진 문자열 집합을 표현하는데 사용하는 형식 언어.

        정규표현식을 이용하면
        입력된 문자열에 대한 특정 조건 검색, 일치 여부 판단, 치환에 대한
        조건문을 간단히 처리할 수 있다.
    </pre>

    <h3>정규 표현식 참고 사이트</h3>
    <a href="https://regexper.com" target="_blank">작성한 정규표현식을 그림으로 나타내주는 사이트</a>
    <a href="https://regexr.com" target="_blank">정규표현식 테스트 사이트</a>



    <hr>

    <h1>정규 표현식 객체 생성 및 확인하기</h1>

    <pre>
        1. 정규 표현식 객체 생성 방법

        1) const regExp = new RegExp("정규표현식");
        2) const regExp = /정규표현식/;
            -> 양쪽 '/' 기호 정규 표현식의 리터럴 표기법

        2. 문자열 패턴 확인 메서드(함수)

        1) regExp.test(문자열)
        -> 문자열에 정규표현식과 일치하는 패턴이 있을 경우 true, 없으면 false

        2) regExp.exec(문자열)
        -> 문자열에 정규표현식과 일치하는 패턴이 있을 경우
        처음 매칭되는 문자열을 반환
        없으면 null 반환
    </pre>

    <button id="check1">확인하기</button>


    <hr>

    <h1>정규표현식의 메타 문자</h1>

    <pre>
        문자열의 패턴을 나타내는 문자.
        문자마다 지정된 특별한 뜻이 담겨있다.

        a (일반문자열) : 문자열 내에 a라는 문자열이 존재하는 검색
        [abcd] : 문자열 내에 a,b,c,d 중 하나라도 일치하는 문자가 있는지 검색
        ^ (캐럿) : 문자열의 시작을 의미
        $ (달러) : 문자열의 끝을 의미

        \w (단어) : 아무 글자(단, 띄어쓰기, 특수문자, 한글 X)
        \d (숫자) : 아무 숫자 (0~9 중 하나)
        \s (공간) : 아무 공백 문자(띄어쓰기, 엔터, 탭 등)

        [0-9] : 0부터 9까지 모든 숫자
        [ㄱ-힣] : ㄱ부터 힣 까지 모든 한글 
        [a-z] : 모든 영어 소문자
        [A-Z] : 모든 영어 대문자 

        * 특수문자의 경우 각각을 입력하는 방법밖엔 없음

        * 수량 관련 메타 문자
        a{5} : a문자가 5개 존재
        a{2,5} : a가 2개 이상 5개이하
        a{2,} : a가 2개 이상
        a{,5} : a가 5개 이하

        * : 0개 이상 
        + : 1개 이상
        ? : 0개 또는 1개
        . : 1칸 (개행문자를 제외한 문자 하나)

        \*, \+, \?, \.

    </pre>

    <button id="btn1">확인하기</button>

    <div id="div1" class="area"></div>


    <hr>

    <h3>이름 유효성 검사</h3>

    <h5>한글 2~5글자</h5>
    이름 : <input type="text" id="inputName"> <br>
    <span id="inputNameResult"></span>


    <hr>
    <h3>주민등록번호 유효성검사</h3>
    주민등록번호 : <input id="inputPno"> <br>
    <span id="inputPnoResult"></span>




    <div style="height: 500px;"></div>
    <script src="js/07_정규표현식.js"></script>
</body>
</html>

07_정규표현식.js

// 정규 표현식 객체 생성 + 확인하기
document.getElementById("check1").addEventListener("click", function() {

    // 정규표현식 객체 생성
    const regExp1 = new RegExp("script");
                // "script"와 일치하는 문자열이 있는지 검사하는 정규표현식
    
    const regExp2 = /java/;
            // "java"와 일치하는 문자열이 있는지 검사하는 정규표현식

    // 확인하기
    const str1 = "저희는 지금 javascript를 공부하고 있습니다.";
    const str2 = "servlet/jsp(java server page)도 조만간 할겁니다";
    const str3 = "java, java, java";

    console.log(  "regExp1.test(str1) : " +  regExp1.test(str1) );
    console.log( regExp1.exec(str1) );

    console.log(  "regExp2.test(str2) : " +  regExp2.test(str2) );
    console.log( regExp2.exec(str2) );

    // 일치하는게 없는 경우
    console.log(  "regExp1.test(str2) : " +  regExp1.test(str2) );
    console.log( regExp1.exec(str2) );

    // 일치하는게 여러개 있을 경우
    console.log(  "regExp2.test(str3) : " +  regExp2.test(str3) );
    console.log( regExp2.exec(str3) );
});


// 메타문자 확인하기
document.getElementById("btn1").addEventListener("click", function() {

    const div1 = document.getElementById("div1");

    // a (일반문자열) : 문자열 내에 a라는 문자열이 존재하는 검색
    const regExp1 = /a/;
    div1.innerHTML += "/a/, apple : " + regExp1.test("apple") + "<hr>"; // true
    div1.innerHTML += "/a/, price : " + regExp1.test("price") + "<hr>"; // false

    // [abcd] : 문자열 내에 a,b,c,d 중 하나라도 일치하는 문자가 있는지 검색
    const regExp2 = /[abcd]/;
    div1.innerHTML += "/[abcd]/, apple : " + regExp2.test("apple") + "<hr>"; // true
    div1.innerHTML += "/[abcd]/, ssbss : " + regExp2.test("ssbss") + "<hr>"; // true
    div1.innerHTML += "/[abcd]/, qwerty : " + regExp2.test("qwerty") + "<hr>"; // false

    //  ^ (캐럿) : 문자열의 시작을 의미
    const regExp3 = /^group/; // 문자열의 시작이 group인 확인
    div1.innerHTML += "/^group/, group100 : " + regExp3.test("group100") + "<hr>"; // true
    div1.innerHTML += "/^group/, 100group : " + regExp3.test("100group") + "<hr>"; // false

    // $ (달러) : 문자열의 끝을 의미
    const regExp4 = /group$/; // 문자열의 끝이 group인 확인
    div1.innerHTML += "/^group/, group100 : " + regExp4.test("group100") + "<hr>"; // false
    div1.innerHTML += "/^group/, 100group : " + regExp4.test("100group") + "<hr>"; //  true
});

// 이름 유효성 검사
document.getElementById("inputName").addEventListener("keyup", function() {

    // 결과 출력용 span
    const span = document.getElementById("inputNameResult");

    // 한글 2~5글자 정규 표현식 
    const regExp = /^[가-힣]{2,5}$/;

    // 빈칸인지검사
    if(this.value.length == 0) {
        span.innerText = "";
        return; 
    }

    // 유효성 검사
    if( regExp.test(this.value) ){
        // 유효한 경우
        span.innerText = "유효한 이름 형식입니다";
        span.style.color = "green";
        span.style.fontWeight = "bold";
    } else {
        span.innerText = "이름 형식이 유효하지 않습니다";
        span.style.color = "red";
        span.style.fontWeight = "bold";
    }

});


// 주민등록번호 정규식 검사
document.getElementById("inputPno").addEventListener("keyup", function() {

    const span = document.getElementById("inputPnoResult");

    if(this.value.length == 0) {

        span.innerText = "주민등록번호를 작성해주세요";
        
        span.classList.remove("confirm");
        span.classList.remove("error");

        return;

    }

    // 생년월일(6)-고유번호(7)
    const regExp = /^\d{6}\-\d{7}$/;

    if(regExp.test(this.value)) {
        span.innerText = "유효한 주민등록번호 형식입니다."

        span.classList.remove("error"); 
        span.classList.add("confirm");
    } else {
        span.innerText = "유효하지 않습니다."

        span.classList.remove("confirm");
        span.classList.add("error");
    }
});



회원가입양식.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>회원가입양식</title>
    <style>
        .btn-area{ text-align: right; }
        td{ padding: 5px; }
        fieldset{ width: 430px;}
        span{font-size: 14px;}
        .confirm{ color : green; }
        .error{ color : red; }
    </style>
</head>
<body>
    <form action="main.html" method="post" onsubmit="return validate()">
        <fieldset>
            <legend>회원 가입 양식</legend>

            <table>
                <tr>
                    <td>아이디</td>
                    <td>
                        <input type="text" id="inputId">
                    </td>
                    <td>
                        <button type="button">중복확인</button>
                    </td>
                </tr>
                <tr>
                    <td>비밀번호</td>
                    <td>
                        <input type="password" id="inputPw">
                    </td>
                    <td>
                        <span id="pwMessage"></span>
                    </td>
                </tr>
                <tr>
                    <td>비밀번호확인</td>
                    <td>
                        <input type="password" id="inputPwConfirm">
                    </td>
                    <td></td>
                </tr>
                <tr>
                    <td>이름</td>
                    <td>
                        <input type="text" id="inputName">
                    </td>
                    <td>
                        <span id="nameMessage"></span>
                    </td>
                </tr>
                <tr>
                    <td>성별</td>
                    <td>
                        <label><input type="radio" name="gender" value="m"></label> 
                        <label><input type="radio" name="gender" value="f"></label> 
                    </td>
                    <td></td>
                </tr>
                <tr>
                    <td>전화번호</td>
                    <td>
                        <input type="text" id="inputTel">
                    </td>
                    <td></td>
                </tr>
                <tr>
                    <td>이메일</td>
                    <td>
                        <input type="text" id="inputEmail">
                    </td>
                    <td></td>
                </tr>
                <tr>
                    <td></td>
                    <td class="btn-area">
                        <button type="reset">초기화</button>
                        <button>회원가입</button>
                    </td>
                    <td></td>
                </tr>
            </table>
        </fieldset>
    </form>

    <script src="js/회원가입양식.js"></script>
</body>
</html>

회원가입양식.js

// 유효성 검사 객체
const checkObj = {
    "inputId" : false, // 아이디
    "inputPw" : false, // 비밀번호
    "inputPwConfirm" : false, // 비번확인
    "inputName" : false, // 이름
    "gender" : false, // 성별
    "inputTel" : false // 전화번호
}


/** 아이디 : 값이 변했을 때
 * 영어 소문자로 시작하고,
영어 대/소문자, 숫자, - , _ 로만 이루어진 6~14 글자 사이 문자열인지 검사
아이디 정규표현식 : (각자 작성)
- 형식이 일치할 경우
입력창의 배경색을 springgreen 으로 변경 */

document.getElementById("inputId").addEventListener("change", function() {

    const regExp = /^[a-z][\w-_]{5,13}$/;
                // 소문자시작(1) + 나머지(5~13) = 6~14글자

    if(regExp.test(this.value)) {
        this.style.backgroundColor = "springgreen";
        this.style.color = "black";
        checkObj.inputId = true;
    } else {
        this.style.backgroundColor = "red";
        this.style.color = "white";
        checkObj.inputId = false;
    }


});

/*** 
 * 비밀번호, 비밀번호 확인 : 키보드가 올라올 때
"비밀번호" 를 미입력한 상태에서 "비밀번호 확인"을 작성할 경우
"비밀번호 확인"에 작성된 내용을 모두 삭제하고
'비밀번호를 입력해주세요' 경고창 출력 후
focus 를 "비밀번호" 입력창으로 이동 */

const inputPw = document.getElementById("inputPw");
const inputPwConfirm = document.getElementById("inputPwConfirm");

inputPwConfirm.addEventListener("keyup", function() {

    if(inputPw.value.length == 0) {
        this.value = "";
        alert("비밀번호를 입력해주세요");
        inputPw.focus();
        checkObj.inputPw = false;
    }
});

/** 
 * - 비밀번호가 일치할 경우
"비밀번호" 입력창 오른쪽에 "비밀번호 일치" 글자를 초록색으로 출력.
 * 
- 비밀번호가 일치하지 않을 경우
"비밀번호" 입력창 오른쪽에 "비밀번호가 불일치" 글자를 빨간색으로 출력.
 */

const pwMessage = document.getElementById("pwMessage");

inputPw.addEventListener("keyup", function() {

    if( (inputPw.value == inputPwConfirm.value) && inputPw.value.length != 0 ) {
        pwMessage.innerText = "비밀번호 일치";
        pwMessage.classList.add("confirm");
        pwMessage.classList.remove("error");
        checkObj.inputPw = true;
        checkObj.inputPwConfirm = true;
    }else {
        pwMessage.innerText="비밀번호 불일치";
        pwMessage.classList.add("error");
        pwMessage.classList.remove("confirm");
        checkObj.inputPwConfirm = false;
    }
});

inputPwConfirm.addEventListener("keyup", function() {
    if( (inputPw.value == inputPwConfirm.value) && inputPw.value.length != 0 ) {
        pwMessage.innerText = "비밀번호 일치";
        pwMessage.classList.add("confirm");
        pwMessage.classList.remove("error");
        checkObj.inputPw = true;
        checkObj.inputPwConfirm = true;
    }else {
        pwMessage.innerText="비밀번호 불일치";
        pwMessage.classList.add("error");
        pwMessage.classList.remove("confirm");
        checkObj.inputPwConfirm = false;
    }
});

/*
* 이름 : 값이 변화했을 때
한글 2~5 글자 사이 문자열인지 검사.
이름 정규표현식 : /^[가-힣]{2,5}$/
- 형식이 일치할 경우
"이름" 입력창 오른쪽에 "정상입력" 글자를 초록색으로 출력.
- 형식이 일치할 경우
"이름" 입력창 오른쪽에 "한글만 입력하세요" 글자를 빨간색으로 출력.
*/

document.getElementById("inputName").addEventListener("change", function() {
    const regExp = /^[가-힣]{2,5}$/;

    const nameMessage = document.getElementById("nameMessage");

    if(regExp.test(this.value)) {
        nameMessage.innerText = "정상입력";
        nameMessage.classList.add("confirm");
        nameMessage.classList.remove("error");
        checkObj.inputName = true;
    }else {
        nameMessage.innerText = "한글만 입력하세요";
        nameMessage.classList.add("error");
        nameMessage.classList.remove("confirm");
        checkObj.inputName = false;
    }
});


/*
 회원가입 버튼 클릭 시 : validate() 함수를 호출하여
성별이 선택 되었는지, 전화번호가 형식에 알맞게 작성되었는지 검사 */

function validate() {
    /*
    - 성별이 선택되지 않은 경우
    "성별을 선택해주세요." 경고창(==대화상자) 출력 후
    submit 기본 이벤트를 제거하여 회원가입이 진행되지 않게 함.
    */
    const gender = document.getElementsByName("gender");

    if(!gender[0].checked && !gender[1].checked) {
        alert("성별을 선택해주세요.");
        checkObj.gender = false;

        return false;
    }else {
        checkObj.gender = true;
    }

    /*전화번호 정규 표현식 : /^[0][0-9]{1,2}-[0-9]{3,4}-[0-9]{4}/
    - 전화번호 형식이 올바르지 않을 경우
    "전화번호의 형식이 올바르지 않습니다" 경고창(==대화상자) 출력 후
    submit 기본 이벤트를 제거하여 회원가입이 진행되지 않게 함. */

    const inputTel = document.getElementById("inputTel");
    const regExp = /^[0][0-9]{1,2}-[0-9]{3,4}-[0-9]{4}/;

    if(!regExp.test(inputTel.value)) {
        alert("전화번호의 형식이 올바르지 않습니다.");
        checkObj.inputTel = false;
        return false;
    }else {
        checkObj.inputTel = true;
    }


    // checkObj가 전부 true일때 == 모든 유효성검사를 통과했을 때 ==> 회원가입
    for(let key in checkObj) {
        if( !checkObj[key] ) { // 1 ) checkObj["inputTel"] ==> false
            return false;
        }
    }

    alert("회원가입 완료");
    return true;

}

profile
초보자

0개의 댓글