Project/AWS-Front

화면 프로젝트 (4) - AWS 풀스택 과정 28일차

awspspgh 2024. 8. 22. 18:25

▣ 회원가입 초안

- html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="../css/join.css">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
</head>
<body>
    <div class="inner">
        <div class="top-image">
            <a href=""><img src="../img/img_ezenInside2.png" alt=""></a>
        </div>
        <div class="ess">
            <span class="red">*</span>
            <span>필수입력사항</span>
        </div>
        <form action="">
            <div class="middle-information">
                <div class="information">
                    <div class="id">
                        <span>아이디</span>
                        <span class="red">*</span>
                        <input type="text" class="in" id="username" placeholder="아이디를 입력해주세요.">
                        <input type="button" class="check-btn" value="중복확인">
                    </div>
                    <ul class="List">
                        <li class="success-message hide">O 사용 가능한 아이디입니다.</li>
                        <li class="failure-message hide">X 6자 이상의 영문 혹은 숫자를 조합해야 합니다.</li>
                    </ul>
                    <div class="pw">
                        <span>비밀번호</span>
                        <span class="red">*</span>
                        <input type="text" class="in" id="password" placeholder="비밀번호를 입력해주세요.">
                    </div>
                    <ul class="List">
                        <li class="success-message2 hide">O 사용 가능한 비밀번호입니다.</li>
                        <li class="failure-message2 hide">X 8글자 이상, 영문/숫자/특수문자(공백 제외)를 조합해야 합니다.</li>
                    </ul>
                    <div class="pw-check">
                        <span>비밀번호확인</span>
                        <span class="red">*</span>
                        <input type="text" class="in" id="password-retype" placeholder="동일한 비밀번호를 입력해주세요.">
                    </div>
                    <ul class="List">
                        <li class="mismatch-message hide">O 동일한 비밀번호입니다.</li>
                    </ul>
                    <div class="name">
                        <span>이름</span>
                        <span class="red">*</span>
                        <input type="text" class="in" placeholder="이름을 입력해주세요.">
                    </div>
                    <div class="email">
                        <span>이메일</span>
                        <span class="red">*</span>
                        <input type="text" class="in" placeholder="이메일을 입력해주세요.">
                        <input type="button" class="check-btn" value="중복확인">
                    </div>
                    <div class="phoneNumber">
                        <span>전화번호</span>
                        <span class="red">*</span>
                        <input type="text" class="in" placeholder="숫자만 입력해주세요.">
                        <input type="button" class="check-btn" value="인증번호 받기">
                    </div>
                    <div class="address">
                        <span>주소</span>
                        <span class="red">*</span>
                        <span>
                            <button type="button" class="addressBtn" id="addressBtn" onclick="sample6_execDaumPostcode()">
                                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-search" viewBox="0 0 16 16">
                                    <path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001q.044.06.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1 1 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0"/>
                                </svg>
                                주소 검색
                            </button>
                            <br>
                        </span>
                        <div>
                            <input type="text" class="address-box" id="sample6_postcode" placeholder="우편번호">
                            <input type="text" class="address-box" id="sample6_address" placeholder="주소"><br>
                            <input type="text" class="address-box" id="sample6_detailAddress" placeholder="상세주소">
                            <input type="text" class="address-box" id="sample6_extraAddress" placeholder="참고항목">
                        </div>
                    </div>
                    <div class="gender">
                        <span>성별</span>
                        <span class="radio-check">
                            <label>
                              <input type="radio" name="contact" value="email">
                              <span>남성</span>
                            </label>
                            <label>
                              <input type="radio" name="contact" value="phone">
                              <span>여성</span>
                            </label>
                            <label>
                              <input type="radio" name="contact" value="mail" />
                              <span>상관없음</span>
                            </label>
                        </span>
                    </div>
                    <div class="birth">
                        <span>생년월일</span>
                        <span class="birth-container">
                            <input type="text" class="birth-box" placeholder="YYYY">
                            <span>/</span>                
                            <input type="text" class="birth-box" placeholder="MM">
                            <span>/</span>                
                            <input type="text" class="birth-box" placeholder="DD">                
                        </span>
                    </div>
                    <div class="entrance">
                        <span>입학연도</span>
                        <span class="red">*</span>
                        <span>
                            <select id="entrance-list">
                                <option value="">연도 선택(학번)</option>
                                <option value="2024">2024학번</option>
                                <option value="2023">2023학번</option>
                                <option value="2022">2022학번</option>
                                <option value="2021">2021학번</option>
                                <option value="2020">2020학번</option>
                                <option value="2019">2019학번</option>
                                <option value="2018">2018학번</option>
                                <option value="2017">2017학번</option>
                                <option value="2016">2016학번</option>
                                <option value="2015">2015학번</option>
                                <option value="2014">2014학번</option>
                                <option value="2013">2013학번</option>
                                <option value="2012">2012학번</option>
                                <option value="2011">2011학번</option>
                                <option value="2010">2010학번</option>
                                <option value="2009">2009학번</option>
                                <option value="2008">2008학번</option>
                                <option value="2006">2007학번</option>
                                <option value="2007">2006학번</option>
                                <option value="2005">2005학번</option>
                                <option value="2004">2004학번</option>
                                <option value="2003">2003학번</option>
                                <option value="2002">2002학번</option>
                                <option value="2001">2001학번</option>
                                <option value="2000">2000학번</option>
                                <option value="1999">1999학번</option>
                                <option value="1998">1998학번</option>
                                <option value="1997">1997학번</option>
                                <option value="1996">1996학번</option>
                                <option value="1999">1995학번</option>
                            </select>
                        </span>
                    </div>
                    <div class="college">
                        <span>대학교</span>
                        <span class="red">*</span>
                        <input type="text" class="in inn" placeholder="학교 이름을 입력해주세요.">
                    </div>
                    <div class="major">
                        <span>학과 / 학부</span>
                        <span class="red">*</span>
                        <input type="text" class="in inn" placeholder="학과 또는 학부 이름을 입력해주세요.">
                    </div>
                </div>
            </div>
            <div class="bottom-consent">
                <span>이용약관동의</span>
                <span class="red">*</span>
                <span class="consent">
                    <div class="bottom-title">
                        <input type="checkbox" class="checkbox" id="allCheck" name="consentCheck" style="width: 20px; height: 20px;" onclick="selectAll(this)">
                        <label for="allCheck">전체 동의합니다.</label>
                    </div>
                    <div>
                        <input type="checkbox" class="checkbox" id="one" name="consentCheck" style="width: 20px; height: 20px; margin-top: 5px;">
                        <label for="one">이용약관 동의</label>
                        <span class="red">(필수)</span>
                        <a href="">
                            <span class="clauseFirst">약관보기 ></span>
                        </a>
                    </div>
                    <div>
                        <input type="checkbox" class="checkbox" id="two" name="consentCheck" style="width: 20px; height: 20px; margin-top: 5px;">
                        <label for="two">개인정보 수집·이용 동의</label>
                        <span class="red">(필수)</span>
                        <a href="">
                            <span class="clause">약관보기 ></span>
                        </a>
                    </div>
                    <div>
                        <input type="checkbox" class="checkbox" id="three" name="consentCheck" style="width: 20px; height: 20px; margin-top: 5px;">
                        <label for="three">개인정보 수집·이용 동의</label>
                        <span class="red">(선택)</span>
                        <a href="">
                            <span class="clause">약관보기 ></span>
                        </a>
                    </div>
                    <div>
                        <input type="checkbox" class="checkbox" id="four" name="consentCheck" style="width: 20px; height: 20px; margin-top: 5px;">
                        <label for="four">정보 수신 동의</label>
                        <span class="red">(선택)</span>
                    </div>
                    <div>
                        <input type="checkbox" class="checkbox" id="five" name="consentCheck" style="width: 20px; height: 20px; margin-top: 5px;">
                        <label for="five">본인은 만 14세 이상입니다.</label>
                        <span class="red">(필수)</span>
                    </div>
                    <div class="joinBtn"><input type="button" class="signup" value="가입하기"></div>
                </span>
            </div>
        </form>
    </div>
    <script src="//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"></script>
    <script src="../js/join.js"></script>
</body>
</html>

 

- css

@font-face {
    font-family: "NotoSansKR";
    src: url(../font/NotoSansKR-VariableFont_wght.ttf);
}
body {
    font-family: "NotoSansKR";
}
.inner{
    width: 1280px;
}
.red{
    color: #FFA100;
    font-size: 15px;
    font-weight: 700;
}
.inner>.top-image{
    width: 100%;
}
.inner>.ess{
    position: absolute;
    top: 27%;
    left: 66%;
}
.inner>.top-image>a>img{
    width: 240px;
    position: absolute;
    top: 15%;
    left: 50%;
    transform: translate(-50%, -50%);
}
.inner>form>.middle-information{
    position: absolute;
    width: 960px;
    border-top: 5px solid #737373;
    border-bottom: 5px solid #737373;
    top: 30%;
    left: 50%;
    transform: translate(-50%);
    padding: 20px 0 20px 150px;
}
.inner>form>.middle-information>.information{
    width: 650px;
}
.inner>form>.middle-information>.information .check-btn{
    margin-left: 10px;
    padding: 5px 20px;
    border: 2px solid #FFA100;
    color: #FFA100;
    font-size: 15px;
    font-weight: 500;
    /* 형광펜 css */
    background: linear-gradient(to right, transparent 50%, #FF9900 50%) ;
    background-size: 200%;
    font-weight: 700;
    transition: .25s;
}
.inner>form>.middle-information>.information .check-btn:hover{
    color: white;
    /* 형광펜 css */
    background-position: -100%,0;
}
.in{
    width: 350px;
    height: 45px;
    padding: 10px;
    box-sizing: border-box;
    margin-bottom: 10px;
    border: 3px solid #a6a6a625;
    outline: none;
    font-size: 15px;
    font-weight: 500;
}
.inner>form>.middle-information>.information>ul{
    margin: 0 0 20px 110px;
}
.inner>form>.middle-information>.information>ul>li{
    margin: 0 5px 5px 5px;
    list-style: none;
}
.inner>form>.middle-information>.information>.id>.in{
    margin-left: 70px;
}
.inner>form>.middle-information>.information>.pw>.in{
    margin-left: 55px;
}
.inner>form>.middle-information>.information>.pw-check{
    margin-bottom: 15px;
}
.inner>form>.middle-information>.information>.pw-check>.in{
    margin-left: 25px;
}
.inner>form>.middle-information>.information>.name{
    margin-bottom: 15px;
}
.inner>form>.middle-information>.information>.name>.in{
    margin-left: 90px;
}
.inner>form>.middle-information>.information>.email{
    margin-bottom: 15px;
}
.inner>form>.middle-information>.information>.email>.in{
    margin-left: 75px;
}
.inner>form>.middle-information>.information>.phoneNumber{
    margin-bottom: 15px;
}
.inner>form>.middle-information>.information>.phoneNumber>.in{
    margin-left: 60px;
}
.inner>form>.middle-information>.information>.address>span>.addressBtn{
    margin-left: 92px;
    width: 351px;
    height: 45px;
    background-color: white;
    border: 3px solid #FFA100;
    color: #FFA100;
    font-size: large;
    font-weight: 700;
    /* 형광펜 css */
    background: linear-gradient(to right, transparent 50%, #FF9900 50%) ;
    background-size: 200%;
    font-weight: 700;
    transition: .25s;
}
.inner>form>.middle-information>.information>.address>span>.addressBtn:hover{
    color: white;
    /* 형광펜 css */
    background-position: -100%,0;
}
.bi-search{
    margin-bottom: 3px;
}
.inner>form>.middle-information>.information>.address>div{
    margin: 30px 0 15px 140px;
}
.inner>form>.middle-information>.information>.address>div>.address-box{
    width: 175px;
    height: 30px;
    margin-bottom: 5px;
    padding: 10px;
    box-sizing: border-box;
    margin-bottom: 10px;
    border: 3px solid #a6a6a625;
    outline: none;
    font-size: 15px;
    font-weight: 500;
}

/* radio css 효과 */
label {
    font-size: 18px;
    line-height: 2rem;
    padding: 0.2em 0.4em;
}

[type="radio"], span {
    vertical-align: middle;
}

[type="radio"] {
    appearance: none;
    border: max(2px, 0.1em) solid gray;
    border-radius: 50%;
    width: 1.25em;
    height: 1.25em;
    transition: border 0.2s ease-in-out;
}
[type="radio"]:checked {
    border: 0.4em solid #FF9900;
}

[type="radio"]:focus-visible {
    outline-offset: max(2px, 0.1em);
    outline: max(2px, 0.1em) dotted #FF9900;
}

[type="radio"]:hover {
    box-shadow: 0 0 0 max(4px, 0.2em) lightgray;
    cursor: pointer;
}

[type="radio"]:hover + span {
    cursor: pointer;
}

/* Global CSS */

*,
*::before,
*::after {
box-sizing: border-box;
}

.inner>form>.middle-information>.information>.gender{
    display: flex;
    align-items: center;
    margin-bottom: 15px;
}
.inner>form>.middle-information>.information>.gender>.radio-check{
    margin-left: 85px;
}
.inner>form>.middle-information>.information>.gender>.radio-check>label{
    margin: 0 20px;
}
.inner>form>.middle-information>.information>.birth{
    margin-bottom: 15px;
}
.inner>form>.middle-information>.information>.birth>.birth-container{
    display: inline-block;
    width: 360px;
    border: 3px solid #a6a6a625;
    margin-left: 70px;
}
.inner>form>.middle-information>.information>.birth>.birth-container>span{
    position: absolute;
    line-height: 45px;
    color: #737373;
}
.inner>form>.middle-information>.information>.birth>.birth-container>.birth-box{
    width: 60px;
    height: 45px;
    padding: 10px;
    border: none;
    outline: none;
    font-size: 15px;
    font-weight: 500;
    margin: 0 20px 0 35px;
}
.inner>form>.middle-information>.information>.birth>.birth-container>.birth-box:first-child{
    margin-left: 34px;
}
.inner>form>.middle-information>.information>.entrance{
    margin-bottom: 15px;
}
.inner>form>.middle-information>.information>.entrance>span>select{
    margin-left: 55px;
    padding: 10px;
    width: 360px;
    height: 45px;
    border: 3px solid #a6a6a625;
    color: #737373;
}
.inn{
    width: 360px;
}
.inner>form>.middle-information>.information>.college{
    margin-bottom: 15px;
}
.inner>form>.middle-information>.information>.college>.in{
    margin-left: 70px;
}
.inner>form>.middle-information>.information>.major{
    margin-bottom: 15px;
}
.inner>form>.middle-information>.information>.major>.in{
    margin-left: 38px;
}

.inner>form>.bottom-consent{
    position: absolute;
    width: 980px;
    top: 140%;
    left: 50%;
    background-color: none;
    transform: translate(-50%);
    padding: 20px 0 20px 150px;
    display: flex;
}
.inner>form>.bottom-consent>.consent{
    margin-left: 30px;
}
.inner>form>.bottom-consent>.consent>div{
    margin: 20px;
}
.inner>form>.bottom-consent>.consent>.bottom-title>div{
    font-size: 15px;
    font-weight: 700;
}
.inner>form>.bottom-consent>.consent>div>.checkbox{
    accent-color: #FF9900;
    margin-right: 20px;
    vertical-align: text-top;
}
.inner>form>.bottom-consent>.consent>div>a{
    font-size: 15px;
    font-weight: 500;
    text-decoration: none;
    color: #FF9900;
}
.inner>form>.bottom-consent>.consent>div>a>.clause{
    margin-left: 200px;
}
.inner>form>.bottom-consent>.consent>div>a>.clauseFirst{
    margin-left: 280px;
}
.joinBtn>input{
    margin: 50px 0 0 5px;
    width: 351px;
    height: 45px;
    background-color: white;
    border: 3px solid #FFA100;
    color: #FFA100;
    font-size: large;
    font-weight: 700;
    /* 형광펜 css */
    background: linear-gradient(to right, transparent 50%, #FF9900 50%) ;
    background-size: 200%;
    font-weight: 700;
    transition: .25s;
}
.joinBtn>input:hover{
    color: white;
    /* 형광펜 css */
    background-position: -100%,0;
}

 

- js

// 카카오 주소 api
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();
}

// 체크박스 모두 체크
function selectAll(selectAll)  {
    const checkboxes 
       = document.querySelectorAll('input[type="checkbox"]');
    
    checkboxes.forEach((checkbox) => {
      checkbox.checked = selectAll.checked
    })
};

 

▷ 출력

 

◈ 형광펜 효과

- html

<p>일상에 마주하는 불편함을 <span>새로운 가능성으로 만들겠습니다.</span></p>

 

- css

span{
  background: linear-gradient(to right, transparent 50%, #ddbdd5 50%) ;
  background-size: 200%;
  font-weight: 700;
  transition: .35s;
}

span:hover{
  background-position: -100%,0;
}

 

- background에서 linner-gradient를 이용해 오른쪽으로 절반은 투명, 절반은 원하는 색을 넣어줍니다.

- background-size를 이용해 투명한 부분만 보이도록 200%로 지정해줍니다.

- hover시 background-position에 x축의 -100%를 주어 색상을 입력한 절반 부분이 보이도록 해줍니다.

-> 인라인 속성(display:inline)이거나 인라인 요소(span, a, img..)이어야만 효과를 볼 수 있습니다.

▷ 출력

 

◈ radio 스타일링

- html

<fieldset>
  <label>
    <input type="radio" name="contact" value="email" checked />
    <span>이메일</span>
  </label>

  <label>
    <input type="radio" name="contact" value="phone" />
    <span>전화</span>
  </label>

  <label>
    <input type="radio" name="contact" value="fax" disabled />
    <span>팩스</span>
  </label>

  <label>
    <input type="radio" name="contact" value="mail" />
    <span>우편</span>
  </label>
</fieldset>

 

- css

label {
  font-size: 18px;
  line-height: 2rem;
  padding: 0.2em 0.4em;
}

[type="radio"], span {
  vertical-align: middle;
}

[type="radio"] {
  appearance: none;
  border: max(2px, 0.1em) solid gray;
  border-radius: 50%;
  width: 1.25em;
  height: 1.25em;
  transition: border 0.5s ease-in-out;
}

[type="radio"]:checked {
  border: 0.4em solid tomato;
}

[type="radio"]:focus-visible {
  outline-offset: max(2px, 0.1em);
  outline: max(2px, 0.1em) dotted tomato;
}

[type="radio"]:hover {
  box-shadow: 0 0 0 max(4px, 0.2em) lightgray;
  cursor: pointer;
}

[type="radio"]:hover + span {
  cursor: pointer;
}

[type="radio"]:disabled {
  background-color: lightgray;
  box-shadow: none;
  opacity: 0.7;
  cursor: not-allowed;
}

[type="radio"]:disabled + span {
  opacity: 0.7;
  cursor: not-allowed;
}

/* Global CSS */
fieldset {
  display: flex;
  justify-content: center;
  border: none;
  margin: 0;
  padding: 40px 20px;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

 

- 라디오 버튼과 레이블 텍스트간 정렬

label {
  font-size: 18px;
  line-height: 2rem;
  padding: 0.2em 0.4em;
}

[type="radio"],
span {
  vertical-align: middle;
}

 

- 기본 스타일 제거

[type="radio"] {
  vertical-align: middle;
  appearance: none;
}

 

- 라디오 버튼 스타일

[type="radio"] {
  vertical-align: middle;
  appearance: none;
  border: max(2px, 0.1em) solid gray;
  border-radius: 50%;
  width: 1.25em;
  height: 1.25em;
}

 

- 체크 상태 스타일

[type="radio"]:checked {
  border: 0.4em solid tomato;
}

 

- 포커스 상태 스타일

[type="radio"]:focus-visible {
  outline: max(2px, 0.1em) dotted tomato;
  outline-offset: max(2px, 0.1em);
}

 

- 호버 상태 스타일

[type="radio"]:hover {
  box-shadow: 0 0 0 max(4px, 0.2em) lightgray;
  cursor: pointer;
}

[type="radio"]:hover + span {
  cursor: pointer;
}

 

- 불능 상태 스타일

[type="radio"]:disabled {
  background-color: lightgray;
  box-shadow: none;
  opacity: 0.7;
  cursor: not-allowed;
}

[type="radio"]:disabled + span {
  opacity: 0.7;
  cursor: not-allowed;
}

 

- 애니메이션 효과

[type="radio"] {
  vertical-align: middle;
  appearance: none;
  border: max(2px, 0.1em) solid gray;
  border-radius: 50%;
  width: 1.25em;
  height: 1.25em;
  transition: border 0.5s ease-in-out;
}

 

▷ 출력

 

◈ checkbox 전체 선택 및 해제

- html

<input type='checkbox'
       name='animal' 
       value='selectall'
       onclick='selectAll(this)'/> <b>Select All</b>
<br />
<input type='checkbox'
       name='animal' 
       value='dog'/> 개
<br />
<input type='checkbox' 
       name='animal' 
       value='cat' /> 고양이
<br />
<input type='checkbox' 
       name='animal' 
       value='rabbit' /> 토끼

 

- js

function selectAll(selectAll)  {
  const checkboxes 
       = document.getElementsByName('animal');
  
  checkboxes.forEach((checkbox) => {
    checkbox.checked = selectAll.checked;
  })
}

 

▷ 출력

 

- 느낀 점

회원가입의 유효성 검사가 너무 복잡했던 것 같아서 너무 힘들었다.. 회원가입 코드를 다시 보면서 복습을 해야겠다!