JavaScript/Vanila JS

JavaScript 기초(6)-정규 표현식, 이벤트 핸들러

두설날 2024. 4. 18. 17:25

*이 글을 읽기전에 작성자 개인의견이 있으니, 다른 블로그와 교차로 읽는것을 권장합니다.*

1. 정규 표현식

문자열에서 특정 문자 조합을 찾기 위한 패턴입니다.

    <input type='text' id='userid' name='userid'>
    - 4자이상 20자이하로 체크
    - 특수문자 입력 불가
    - 한글 입력 불가

정규 표현식 표기
    /정규 표현식 패턴/

아이디 패턴 만들기
- 영문 대문자 또는 소문자만 입력 가능합니다.
- 길이는 4자이상 20자이하로 입력 가능합니다.

    /^[A-Za-z]{4,20}$/

이름 패턴 만들기
- 한글만 사용

    /^[가-힣]+$/

휴대폰번호 패턴 만들기
- 정수 3자리 - 정수 3자리 또는 4자리 - 정수 4자리
- 예) 010-1111-1111 또는 010-111-1111

    /^\d{3}-\d{3,4}-\d{4}/

 이메일 패턴 만들기
 - 영문 대문자, 소문자, 숫자 입력
 - 이메일 패턴에 의한 @, .이 포함
 - 예) aaaa@aa.com, dr.aaa@aaa.com, dr-aa@aa.com, dr_aa@aa.com

    /^[A-Za-z0-9\-\.\_]+@[A-Za-z0-9\-]+\.[A-Za-z]+$/


검증하기
test(): 정규표현식에 대입한 문자열이 패턴과 적합하면 true, 아니면 flase를 리턴

    아이디입력: <input type='text' name='userid' id='userid'>

    <script>

  • const userid = document.getElementById('userid');
  • const expIdText = /^[A-Za-z]{4,20}$/;
  • expIdText.test(userid.value); // 적합하면 true, 아니면 false를 리턴
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>회원가입</title>
    <script src="./js/regist.js"></script>
    <script src="//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"></script>
<script>
    function sample6_execDaumPostcode() {
        new daum.Postcode({
            oncomplete: function(data) {
                // 팝업에서 검색결과 항목을 클릭했을때 실행할 코드를 작성하는 부분.
                // 각 주소의 노출 규칙에 따라 주소를 조합한다.
                // 내려오는 변수가 값이 없는 경우엔 공백('')값을 가지므로, 이를 참고하여 분기 한다.
                var addr = ''; // 주소 변수
                var extraAddr = ''; // 참고항목 변수
                //사용자가 선택한 주소 타입에 따라 해당 주소 값을 가져온다.
                if (data.userSelectedType === 'R') { // 사용자가 도로명 주소를 선택했을 경우
                    addr = data.roadAddress;
                } else { // 사용자가 지번 주소를 선택했을 경우(J)
                    addr = data.jibunAddress;
                }
                // 사용자가 선택한 주소가 도로명 타입일때 참고항목을 조합한다.
                if(data.userSelectedType === 'R'){
                    // 법정동명이 있을 경우 추가한다. (법정리는 제외)
                    // 법정동의 경우 마지막 문자가 "동/로/가"로 끝난다.
                    if(data.bname !== '' && /[동|로|가]$/g.test(data.bname)){
                        extraAddr += data.bname;
                    }
                    // 건물명이 있고, 공동주택일 경우 추가한다.
                    if(data.buildingName !== '' && data.apartment === 'Y'){
                        extraAddr += (extraAddr !== '' ? ', ' + data.buildingName : data.buildingName);
                    }
                    // 표시할 참고항목이 있을 경우, 괄호까지 추가한 최종 문자열을 만든다.
                    if(extraAddr !== ''){
                        extraAddr = ' (' + extraAddr + ')';
                    }
                    // 조합된 참고항목을 해당 필드에 넣는다.
                    document.getElementById("sample6_extraAddress").value = extraAddr;
                } else {
                    document.getElementById("sample6_extraAddress").value = '';
                }
                // 우편번호와 주소 정보를 해당 필드에 넣는다.
                document.getElementById('sample6_postcode').value = data.zonecode;
                document.getElementById("sample6_address").value = addr;
                // 커서를 상세주소 필드로 이동한다.
                document.getElementById("sample6_detailAddress").focus();
            }
        }).open();
    }
</script>
</head>
<body>
    <h2>회원가입</h2>
    <form action="/regist" name="regform" id="regform" method="post" onsubmit="return sendit()">
        <input type="hidden" name="ssncheck" id="ssncheck" value="n">
        <p>아이디: <input type="text" name="userid" id="userid" maxlength="20"></p>
        <p>비밀번호: <input type="password" name="userpw" id="userpw" maxlength="20"></p>
        <p>비밀번호 확인: <input type="password" name="userpw_re" id="userpw_re" maxlength="20"></p>
        <p>이름: <input type="text" name="name" id="name" maxlength="10"></p>
        <p>휴대폰번호: <input type="text" name="hp" id="hp" maxlength="20"></p>
        <p>이메일: <input type="text" name="email" id="email" maxlength="50"></p>
        <p>성별: <label for="male">남자</label><input type="radio" name="gender" value="남자" checked> <label for="female">여자</label><input type="radio" name="gender" value=" 여자"></p>
        <p>주민등록번호: <input type="text" name="ssn1" id="ssn1" maxlength="6" class="ssn"> - <input type="password" name="ssn2" id="ssn2" maxlength="7" class="ssn"><button type="button" onclick="checkSSN()" id="checkbtn">주민등록번호검증</button></p>
        <p>우편변호: <input type="text" name="zipcode" maxlength="5" id="sample6_postcode" placeholder="우편번호"><button type="button" onclick="sample6_execDaumPostcode()" value="우편번호 찾기">우편번호 찾기</button></p>
        <p>주소: <input type="text" name="address1" id="sample6_address" placeholder="주소"></p>
        <p>상세주소: <input type="text" name="address2" id="sample6_detailAddress" placeholder="상세주소"></p>
        <p>참고사항: <input type="text" name="address3" id="sample6_extraAddress" placeholder="참고항목"></p>
        <p> <button type="submit">가입완료</button> <button type="reset">다시작성</button></p>
    </form>
</body>
</html>

window.onload : 웹 페이지의 모든 콘텐츠가 로드된 후에 트리거되는 이벤트입니다. 페이지가 완전히 로드된 후에 스크립트를 실행하는 데 사용됩니다.

focus() : 해당 요소로 데이터 입력할 수 있도록 필드 이동

queryselector : getElement가 html원소의 속성을 가져오는 것과 다르게, querySelector는 CSS스타일 속성을 가져옴.

isSsnCheck = false;

window.onload = function(){
    const ssn1 = document.getElementById('ssn1');
    ssn1.addEventListener('keyup', () => {
        if(ssn1.value.length >= 6){
            document.getElementById('ssn2').focus();
        }
    })

    const ssn = document.querySelectorAll('.ssn');
    ssn.forEach((s) => {
        s.addEventListener('input', () => {
            document.getElementById('ssncheck').value = 'n';
        })
    })
}

/* 주민등록 검증 함수 */
function checkSSN() {
    ssn1 = document.getElementById('ssn1').value;
    ssn2 = document.getElementById('ssn2').value;
    const ssn = ssn1 + ssn2
    let result = 0;
    check_num = [2,3,4,5,6,7,8,9,2,3,4,5]
    for(let i = 0; i < 12; i++){
        result += ssn[i] * check_num[i];
    }
    result %= 11
    result = 11 - result
    if (result >= 10){
        result %= 10
    }
    if (result == ssn2[6]){
        alert('유효한 주민번호 형식입니다.')
        document.getElementById('ssncheck').value = 'y'
    } else {
        alert('유효하지 않은 주민번호 형식입니다.')
    }
}
/* onsubmit시 동작 */
function sendit() {
    // alert('폼이 submit 되었음!');
    const userid = document.getElementById('userid')
    const userpw = document.getElementById('userpw')
    const userpwre = document.getElementById('userpw_re')
    const name = document.getElementById('name')
    const hp = document.getElementById('hp')
    const email = document.getElementById('email');
    const ssncheck = document.getElementById('ssncheck');
    const checkbtn = document.getElementById('checkbtn');
    const expIdText = /^[A-Za-z]{4,20}$/;
    const expPwText = /^(?=.*[A-Za-z])(?=.*[!@#$%^&*+=-])(?=.*[0-9]).{4,20}$/;
    const expNameText = /^[가-힣]+$/;
    const expHpText = /^\d{3}-\d{3,4}-\d{4}$/;
    const expEmailText = /^[A-Za-z0-9\-\.\_]+@[A-Za-z0-9\-]+\.[A-Za-z]+$/
    if(!expIdText.test(userid.value)){
        alert('아이디는 4자이상 20자 이하의 영문자로 입력하세요');
        userid.focus();
        return false;
    }
    if(!expPwText.test(userpw.value)){
        alert('비밀번호는 4자이상 20자이하의 영문자, 숫자, 특수문자를 1자이상 꼭 포함해야합니다.');
        userpw.focus();
        return false
    }
    if(!userpw.value == userpwre.value){
        alert('비밀번호와 비밀번호 확인이 일치하지 않습니다.');
        return false
    }
    if(!expNameText.test(name.value)){
        alert('이름은 한글로 입력하세요');
        name.focus();
        return false;
    }
    if(!expHpText.test(hp.value)){
        alert('휴대폰번호 형식이 일치하지 않습니다.');
        console.log(!expHpText.test(hp.value))
        hp.focus();
        return false;
    }
    if(!expEmailText.test(email.value)){
        alert('이메일 형식이 일치하지 않습니다.');
        email.focus();
        return false;
    }
    if(ssncheck.value == 'n'){
        alert('주민등록번호 유효성검사를 해주세요');
        checkbtn.focus();
        return false;
    }
    return true;
}

2. 이벤트(Event)

- 웹브라우저가 알려주는 HTML 요소에 대한 사건이 발생
- 웹페이지에 사용된 자바스크립트는 발생한 이벤트에 반응하여 특정 동작을 수행할 수 있습니다.
- 자바스크립트는 비동기식 이벤트 중심의 프로그래밍 모델입니다.

    <inpu type='button' onclick='sendit()' value='확인>
                ------  ------- ---------
                이벤트타겟 이벤트타임 이벤트리스너

    <button type='button' onclick='sendit()'>확인</button>
    -------                  -----------
    이벤트 타겟                이벤트타입

이벤트 타겟(Event Target)
이벤트가 일어날 객체를 의미합니다.

이벤트 타입(Event Type)
- 발생한 이벤트의 종류를 나타내는 문자열로 이벤트명이라고도 부릅니다.
- 키보드, 마우스, HTML DOM, window객체 ...등을 처리하는 이벤트를 제공합니다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>이벤트 타입</title>
    <script>
        window.onload = function(){
            const text =document.getElementById('text');
            text.innerHTML = "<strong style='color:deeppink';>HTML 문서가 로드 되었습니다</strong>";
        }
        function changeText(el){
            // el = document.getElementById('p');
            el.innerHTML = "<strong style='color: deepskyblue;'>문자열이 변경되었습니다!</strong>"

        }
    </script>
</head>
<body>
    <h2>이벤트 타입</h2>
    <p id="text"></p>
    <p onclick="changeText(this)">문자열을 클릭하세요</p>
</body>
</html>

3. 이벤트 리스너(Event Listener)

- 이벤트가 발생했을 때 그 처리를 하는 함수
이벤트 핸들러라고도 부릅니다.
- 지정된 타입의 이벤트가 특정 요소에서 발생하면 웹브라우저는 그 요소에 등록된 이벤트리스너를 실행합니다.

    이벤트 등록
    객체.addEventListener(이벤트타입, 이벤트리스너);

    이벤트 제거
    객체.removeEventListener(이벤트타입, 이벤트리스너);

마우스 이벤트

  • click: 사용자가 요소를 클릭할 때 발생합니다.
  • dblclick: 사용자가 요소를 더블 클릭할 때 발생합니다.
  • mousedown: 사용자가 요소에서 마우스 버튼을 눌렀을 때 발생합니다.
  • mouseup: 사용자가 요소에서 마우스 버튼을 뗄 때 발생합니다.
  • mousemove: 사용자가 요소 위에서 마우스를 움직일 때 발생합니다.
  • mouseover: 사용자가 요소 위로 마우스를 올릴 때 발생합니다.
  • mouseout: 사용자가 요소에서 마우스를 뗄 때 발생합니다.
  • mouseenter: 마우스 커서가 요소에 진입할 때 발생합니다. 버블링이 발생하지 않습니다.
  • mouseleave: 마우스 커서가 요소에서 벗어날 때 발생합니다. 버블링이 발생하지 않습니다.

키보드 이벤트

  • keydown: 사용자가 키보드를 눌렀을 때 발생합니다.
  • keyup: 사용자가 키보드에서 손을 뗄 때 발생합니다.
  • keypress: 사용자가 키보드를 눌렀을 때 발생하며, 텍스트 입력과 관련된 이벤트입니다. 현재는 대부분의 브라우저에서 keypress 이벤트는 keydown 및 keyup 이벤트로 대체되었습니다.

포커스 이벤트

  • focus: 요소가 포커스를 받을 때 발생합니다. 버블링이 발생하지 않습니다.
  • blur: 요소가 포커스를 잃을 때 발생합니다. 버블링이 발생하지 않습니다.
  • focusin: 요소가 포커스를 받을 때 발생합니다. 버블링이 발생합니다.
  • focusout: 요소가 포커스를 잃을 때 발생합니다. 버블링이 발생합니다.

폼 이벤트

  • submit: 폼이 제출될 때 발생합니다.
  • change: 폼 요소의 값이 변경될 때 발생합니다.
  • input: 사용자가 폼 요소에 입력할 때마다 발생합니다.
  • reset: 폼이 리셋될 때 발생합니다.

윈도우 이벤트

  • load: 페이지나 이미지가 완전히 로드될 때 발생합니다.
  • resize: 윈도우의 크기가 변경될 때 발생합니다.
  • scroll: 사용자가 페이지를 스크롤할 때 발생합니다.
  • unload: 사용자가 페이지를 떠날 때 발생합니다.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>이벤트 리스너</title>
    <script>
        let btn;
        window.onload = function(){
            btn = document.getElementById('eventBtn');
            btn.addEventListener('click', clickBtn);
            btn.addEventListener('mouseover', mouseOverBtn);
            btn.addEventListener('mouseout', mouseOutBtn);
            const delbtn = document.getElementById('delBtn');
            delbtn.addEventListener('click', delEvent);
        }
        function clickBtn(){
            document.getElementById('text').innerHTML = '<strong>버튼을 클릭했어요</strong>';
        }
        function mouseOverBtn(){
            document.getElementById('text').innerHTML = '<strong>버튼위에 커서가 올라갔어요</strong>';
        }
        function mouseOutBtn(){
            document.getElementById('text').innerHTML = '<strong>버튼 밖으로 커서가 나갔어요</strong>';
        }
        function delEvent(){
            btn.removeEventListener('click', clickBtn);
            btn.removeEventListener('mouseover', mouseOverBtn);
            btn.removeEventListener('mouseout', mouseOutBtn);
            document.getElementById('text').innerHTML = '<strong>이벤트 핸들러가 삭제됐어요</strong>';
        }
    </script>
</head>
<body>
    <h2>이벤트 리스너</h2>
    <p><button id="eventBtn">이벤트 버튼</button> <button id="delBtn">이벤트 삭제 버튼</button></p>
    <p id="text"></p>
</body>
</html>

4. 이벤트 객체(Event object)

- 특정 타입의 이벤트와 관련이 있는 객체입니다.
- 이벤트 객체는 이벤트 리스너가 호출할 때 인수로 전달합니다.
- 이벤트 객체는 해당 타입의 이벤트에 대한 상세 정보를 저장하고 있습니다.
- 모든 이벤트 객체는 이벤트의 타입을 나타내는 type 프러퍼티와 이벤트 대상을 나타내는 target프로퍼티를 가지고 있습니다.

<button type=button onclick='sendit()'>완료</button>

<script>
function sendit(e){
    ....
    // e.target = button
    // e.type = click
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>이벤트 객체</title>
    <script>
        window.onload = function(){
            const btn = document.getElementById('btn');
            btn.addEventListener('click', clickBtn);
        }
        function clickBtn(e){
            console.log(e);
            console.log(e.target);
            console.log(e.target.id);
            console.log(e.target.value);

            console.log(e.type);
        }
    </script>
</head>
<body>
    <h2>이벤트 객체</h2>
    <button type="button" id="btn" value="확인">확인</button>
</body>
</html>



문제
버튼 2개를 아래와 같이 만들고, 각 버튼을 누르면 콘솔에 "버튼 X가 눌렸어요"를 출력하는 문서를 만들어보자. (단, 이벤트 객체를 활용하고 이벤트 핸들러는 한가지를 사용)

    [버튼1] [버튼2]

버튼1을 클릭했을 경우: 버튼 1이 눌렸어요!
버튼 2를 클릭했을 경우: 버튼 2가 눌렸어요!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>이벤트 객체2</title>
    <script>
        window.onload = function(){
            const btn1 = document.getElementById('btn1');
            const btn2 = document.getElementById('btn2');
            const btn3 = document.getElementById('btn3');

            btn1.addEventListener('click',clickBtn);
            btn2.addEventListener('click',clickBtn);
            btn3.addEventListener('click',(e)=>{console.log('버튼 3이 눌렀어요!')});
        }

        function clickBtn(e){
            switch(e.target.id){
                case 'btn1':
                    console.log('버튼 1이 눌렀어요!');
                    break;
                case 'btn2':
                    console.log('버튼 2이 눌렀어요!');
                    break;
            }
        }
    </script>
</head>
<body>
    <h2>이벤트 객체2</h2>
    <button type="button" id="btn1">버튼1</button> 
    <button type="button" id="btn2">버튼2</button>
    <button type="button" id="btn3">버튼3</button>
</body>
</html>