✿∘˚˳°∘°
46일차 : [실습] 단계형 회원가입 만들기 본문
20230201
<!DOCTYPE html>
<html lang="ko">
<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>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR&display=swap" rel="stylesheet">
<link rel="stylesheet" href="css/join1.css">
</head>
<body>
<div class="wrap">
<ul class="tabs">
<li class="active-tab">약관확인</li>
<li>필수정보입력</li>
<li>상세정보입력</li>
<li>가입완료</li>
</ul>
<!-- 본문4개가 들어갈 부분 -->
<div class="content">
<div class="contentDetail active-content">
<!-- 본문1. 약관확인컨텐츠 -->
<h3 class="title">이용약관 확인 및 동의</h3>
<div>
<input type="checkbox" id="allAgreement">
<label for="allAgreement">이용약관 전체체크</label>
</div>
<div class="agreebox">
<div>
<input type="checkbox" id="privacyAgreement" class="agreeCheck">
<label for="privacyAgreement">개인정보 수집 및 이용에 동의 <span class="fc-blue">(필수)</span></label>
<div class="agreeContent">
<ul>
<li>수집항목 : 이름, 휴대전화번호, 생년월일, 비밀번호</li>
<li>수집/이용목적 : 회원제 서비스 제공</li>
<li>보유 및 이용기간 : 회원탈퇴 시 까지</li>
</ul>
</div>
</div>
</div>
<div class="agreebox">
<div>
<input type="checkbox" id="optionalAgreement" class="agreeCheck">
<label for="optionalAgreement">개인정보 수집 및 이용에 동의 <span class="fc-blue">(선택)</span></label>
<div class="agreeContent">
<ul>
<li>수집항목 : 이름, 휴대전화번호, 생년월일, 비밀번호</li>
<li>수집/이용목적 : 회원제 서비스 제공</li>
<li>보유 및 이용기간 : 회원탈퇴 시 까지</li>
</ul>
</div>
</div>
</div>
<div class="btnBox">
<button class="nextBtn">다음</button>
</div>
</div>
<div class="contentDetail">
<!-- 본문2. 필수정보입력컨텐츠 -->
<h3 class="title">필수정보입력</h3>
<table class="inputTbl">
<tr>
<td><label for="id">아이디</label></td>
<td><input type="text" class="input" name="id" id="id"><span id="idChk"></span></td>
</tr>
<tr>
<td><label for="pw">비밀번호</label></td>
<td><input type="password" class="input" name="pw" id="pw"></td>
</tr>
<tr>
<td><label for="pwRe">비밀번호확인</label></td>
<td><input type="password" class="input" name="pwRe" id="pwRe"><span id="pwChk"</td>
</tr>
<tr>
<td><label for="name">이름</label></td>
<td><input type="text" class="input" name="name" id="name"></td>
</tr>
</table>
<div class="btnBox">
<button class="nextBtn">다음</button>
</div>
</div>
<div class="contentDetail">
<!-- 본문3. 상세정보입력컨텐츠 -->
<h3 class="title">추가정보입력</h3>
<table class="inputTbl">
<tr>
<td>이메일</td>
<td>
<input type="text" class="input short" name="email1">
@
<input type="text" class="input short" name="email2">
<select name="emailSelect" id="emailSelect">
<option value="">직접입력</option>
<option value="naver.com">네이버</option>
<option value="gmail.com">구글</option>
<option value="nate.com">네이트</option>
</select>
</td>
</tr>
<tr>
<td>성별</td>
<td>
<input type="radio" name="gender" value="남" id="m">
<label for="m">남자</label>
<input type="radio" name="gender" value="여" id="f">
<label for="f">여자</label>
</td>
</tr>
<tr>
<td>자기소개</td>
<td>
<!-- 주의점 : 공간을 넓게줬다 - 여러줄을 사용해야함
input태그는 여러줄을 인식하지 못하므로 사용X -->
<textarea id="introduce"></textarea>
</td>
</tr>
</table>
<div class="btnBox">
<button class="nextBtn">다음</button>
</div>
</div>
<div class="contentDetail">
<!-- 본문4 : 가입완료 컨텐츠 -->
<h3 class="title">가입을 축하합니다.</h3>
<button class="nextBtn">로그인하기</button>
<div id="loginFrm">
<div class="inputDiv">
<label for="loginId">아이디</label>
<input type="text" name="loginId" id="loginId" class="input">
</div>
<div class="inputDiv">
<label for="loginPw">비밀번호</label>
<input type="password" name="loginPw" id="loginPw" class="input">
</div>
<div class="btnBox">
<input type="submit" value="로그인" class="nextBtn">
<input type="button" value="취소" class="nextBtn">
</div>
</div>
</div>
</div>
</div>
<script src="js/join1.js"></script>
</body>
</html>
*{
font-family: 'Noto Sans KR', sans-serif;
color: #282828;
margin: 0;
padding: 0;
outline: none;
}
.wrap{
width: 1200px;
margin: 100px auto;
}
/* div는 display:block설정이기 때문에 한줄에 다른 컨텐츠가 올 수 없음
div를 가운데 정렬해주기 위해 1200px이외의 남은부분의 margin을 반으로 나눠
양옆에 제공해주는 margin:0 auto를 사용*/
.tabs{
/*원래 ul의 불릿기호는 기본적으로 padding과 margin을 가지고 있으므로
div내부에 생성됨 -> 전체 마진과 패딩을 날려줘서 div영역 밖에 있는 것 */
list-style-type: none;
/*float 시 부모요소는 높이를 찾지X overflow:hidden을 넣어줘야함*/
overflow: hidden;
}
.tabs>li{
float: left;
width: calc(100%/4);
height: 70px;
text-align: center;
line-height: 70px;
font-size: 18px;
border: 1px solid #d8d8d8;
box-sizing: border-box;
/*width를 전체로 잡아놨는데 border의 1px이 추가되므로
칸을 넘어가게된다 -> box-sizing을 통해 border포함 width를 설정해야줘야함*/
}
.content{
border: 1px solid #d8d8d8;
padding: 30px;
border-top: none;
}
.tabs>li.active-tab{
color: #1f4787;
border-top: 10px solid #1f4787;
font-weight: bold;
line-height: 60px;
border-bottom: none;
}
.contentDetail{
display: none;
}
/* 이 클래스명을 이용해서 컨텐츠를 숨기고 보이고 할 것 */
/*같은클래스명에 우선순위가 동일할 경우 나중에 작성된게 우선순위가 더 높다*/
.active-content{
display: block;
}
.title{
font-size: 30px;
color: #1f4787;
margin-top: 30px;
margin-bottom: 30px;
}
/* 본문1. 약관동의 컨텐츠 */
.agreeContent{
width: 98%;
margin: 0 auto;
border: 1px solid #1f1111;
margin-top: 5px;
padding: 10px;
}
.agreeContent>ul{
list-style-position: inside;
padding-left: 10px;
}
.agreebox{
margin-top: 30px;
}
input[type=checkbox]+label{
font-size: 20px;
}
.fc-blue{
color: #1f4787;
}
.btnBox{
text-align: center;
padding-top: 20px;
}
.nextBtn{
width: 200px;
height: 50px;
background-color: #1f4787;
border: none;
color: #fff;
font-size: 20px;
cursor: pointer;
}
/* 본문2. 필수정보 입력 컨텐츠 */
.inputTbl{
width: 98%;
border-top: 1px solid #1f4787;
border-bottom: 1px solid #b3b3b3;
}
/*tbody를 빼면 디자인이 들어가지 않는다
코드상에서 tbody가 들어가지 않더라도 개발자 도구에서 확인해보면
tbody가 자동으로 들어가있다 - 반드시 넣어야함!*/
.inputTbl>tbody>tr>td{
border-top: 1px solid #ebebeb;
font-size: 20px;
}
.inputTbl>tbody>tr>td:first-child{
/*첫번째 td만 넓이를 지정해주면 다음td는 알아서 설정이된다(남은전체)*/
width: 25%;
background-color: #fbfcfd;
border-right: 1px solid #ebebeb;
padding-left: 20px;
}
.input{
height: 35px;
border: 1px solid #d8d8d8;
font-size: 20px;
width: 400px;
padding-left: 10px;
}
.short{
width: 280px;
}
.input:focus{
border-color : #0e77d9;
}
#emailSelect{
height: 40px;
border: 1px solid #d8d8d8;
font-size: 20px;
width: 200px;
}
input[name=gender]{
display: none;
}
input[name=gender]+label{
display: inline-block;
height: 40px;
line-height: 40px;
width: 150px;
text-align: center;
border: 1px solid #1f4787;
color: #1f4787;
cursor: pointer;
}
input[name=gender]:checked+label{
background-color: #1f4787;
color: #fff
}
#introduce{
width: 600px;
height: 300px;
border: 1px solid #d8d8d8;
font-size: 20px;
resize: none;
}
#introduce:focus{
border: 1px solid #0e77d9;
}
#loginFrm{
width: 50%;
margin: 0 auto;
margin-top: 100px;
font-size: 20px;
display: none;
}
.inputDiv>label{
display: block;
margin-bottom: 20px;
margin-top: 20px;
}
#loginFrm input{
width: 100%;
}
.btnBox>input{
margin-bottom: 20px;
}
const allAgreement = document.querySelector("#allAgreement");
allAgreement.addEventListener("change", function(){
const agreeCheck = document.querySelectorAll(".agreeCheck");
//체크박스의 상태를 가져옴
const status = allAgreement.checked;
/*
if(status){
agreeCheck[0].checked = true;
agreeCheck[1].checked = true;
}else{
agreeCheck[0].checked = false;
agreeCheck[1].checked = false;
}
*/
/*
agreeCheck[0].checked = status;
agreeCheck[1].checked = status;
*/
//체크항목이 여러개면 for문사용
/*
for(let i=0; i<agreeCheck.length; i++){
agreeCheck[i].checked = status;
}
*/
agreeCheck.forEach(function(agree){
agree.checked = status;
});
});
const nextBtn = document.querySelectorAll(".nextBtn");
nextBtn[0].addEventListener("click", function(){
const privacyAgreement = document.querySelector("#privacyAgreement");
const status = privacyAgreement.checked;
if(status){
/*
const tabs = document.querySelectorAll(".tabs>li");
const contentDetail = document.querySelectorAll(".contentDetail");
tabs[0].classList.remove("active-tab");
tabs[1].classList.add("active-tab");
contentDetail[0].classList.remove("active-content");
contentDetail[1].classList.add("active-content");
*/
nextTab(0);
}else{
alert("이용약관 동의를 체크해주세요");
}
});
const memberArr = ['user01', 'user02', 'user03'];
const id = document.querySelector("#id");
const pw = document.querySelector("#pw");
const pwRe = document.querySelector("#pwRe");
const name = document.querySelector("#name");
//아이디와 비밀번호가 정상적으로 들어갔는지 체크할 전역변수
//주의점 : 한글자만 입력했을 경우에도 아이디의 경우 배열에 있는 값과
//다르기때문에 true로 변화
//겹쳤을때 false로 되돌리는 작업을 해줘야함
let idCheckResult = false;
let pwCheckResult = false;
id.addEventListener("keyup", function(){
const inputId = this.value;
const check = memberArr.indexOf(inputId);
const idChk = document.querySelector("#idChk");
if(check == -1){
//사용가능한 아이디인 경우
idChk.innerText = "사용가능한 아이디 입니다.";
idChk.style.color = "#1f4787";
this.style.border = "1px solid #1f4787";
idCheckResult = true;
}else{
//중복인 경우
idChk.innerText = "이미 사용중인 아이디 입니다."
idChk.style.color = "red";
this.style.border = "1px solid red";
idCheckResult = false;
}
});
pw.addEventListener("change", function(){
//비밀번호 확인이 비어있지 않을 때만 동작
const inputPwRe = pwRe.value;
if(inputPwRe != ""){
pwCheck();
}
});
pwRe.addEventListener("change", function(){
pwCheck();
});
function pwCheck(){
const inputPw = pw.value;
const inputPwRe = pwRe.value;
const pwChk = document.querySelector("#pwChk");
if(inputPw == inputPwRe){
pwChk.innerText = "비밀번호가 일치합니다."
pwChk.style.color = "#1f4787";
pw.style.border = "1px solid #1f4787";
pwRe.style.border = "1px solid #1f4787";
pwCheckResult = true;
}else{
pwChk.innerText = "비밀번호가 일치하지 않습니다."
pwChk.style.color = "red";
pw.style.border = "1px solid red";
pwRe.style.border = "1px solid red";
pwCheckResult = false;
}
}
nextBtn[1].addEventListener("click", function(){
if(idCheckResult && pwCheckResult && name.value != ""){
nextTab(1);
}else{
alert("입력값을 확인하세요");
}
});
/*
//0번탭에서 1번탭으로 변경하는 코드
const tabs = document.querySelectorAll(".tabs>li");
const contentDetail = document.querySelectorAll(".contentDetail");
tabs[0].classList.remove("active-tab");
tabs[1].classList.add("active-tab");
contentDetail[0].classList.remove("active-content");
contentDetail[1].classList.add("active-content");
//1번탭에서 2번탭으로 변경하는 코드
const tabs = document.querySelectorAll(".tabs>li");
const contentDetail = document.querySelectorAll(".contentDetail");
tabs[1].classList.remove("active-tab");
tabs[2].classList.add("active-tab");
contentDetail[1].classList.remove("active-content");
contentDetail[2].classList.add("active-content");
*/
//반복됨 -> 함수로 따로빼서 사용
function nextTab(tabNo){
const tabs = document.querySelectorAll(".tabs>li");
const contentDetail = document.querySelectorAll(".contentDetail");
tabs[tabNo].classList.remove("active-tab");
tabs[tabNo+1].classList.add("active-tab");
contentDetail[tabNo].classList.remove("active-content");
contentDetail[tabNo+1].classList.add("active-content");
}
//이메일을 선택하면 email2에 자동으로 들어가는 이벤트
//select에 이벤트를 걸어줘야함(option에는 이벤트를 걸 수 없다)
//option을 선택하면 해당 option의 value가 select의 value로 바뀜
const emailSelect = document.querySelector("#emailSelect");
emailSelect.addEventListener("change", function(){
const selectedValue = emailSelect.value;
console.log(selectedValue);
const emailInput = document.querySelector("[name=email2]");
emailInput.value = selectedValue;
});
nextBtn[2].addEventListener("click", function(){
if(confirm("회원가입을 하시겠습니까?")){
nextTab(2);
}
});
nextBtn[3].addEventListener("click", function(){
const loginFrm = document.querySelector("#loginFrm");
loginFrm.style.display = "block";
});
[ 후기 ]
너무너무어려웠지만 구동되는걸 확인했을 땐 뭔가 뿌듯하기도하고 재미있었다
다만 내가 코드를 짤때는 엄청길어지고 뭔가 조잡해지는데 강사님이 해답코드를 주시면 너무 완벽해서 눈물이난다..^.ㅠ
좀 더 공부해서 나도 깔끔한 코드를 치고싶다~!
'국비수업 > JavaScript' 카테고리의 다른 글
45일차 : [실습] 상품상세페이지만들기 (0) | 2023.02.02 |
---|---|
44일차 : EVENT (0) | 2023.01.30 |
43일차 : [실습]DOM / BOM (0) | 2023.01.30 |
42일차 : DOM (0) | 2023.01.26 |
41일차 : JavaScript의 기본 (0) | 2023.01.25 |
Comments