2015년 1월 3일 토요일

[node 웹페이지 만들기] 1.html 회원가입페이지 만들기


  • node를 공부하며 간단한 웹서버(회원가입페이지) 만들기를 해보려고 합니다.
  • node를 중심으로 웹페이지를 보여주고, DB에 저장,호출해 보려고 합니다.
  • 먼저 view 부분인 html(이후 ejs)부분입니다.
  • 크게 javascript, html, css 부분으로 나눌수 있습니다.
  • 먼저 html 부분입니다.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<!DOCTYPE html>
<html lang='ko'>
<head>
 <meta charset='utf-8'/>
 <title>boards</title>
 <link rel="stylesheet" type="text/css" href="style/mycss2.css">
 <script type="text/javascript" src="js/jquery-1.9.1.min.js"></script>
 <script type="text/javascript" src="js/myscript2.js"></script>
</head>
<body>
 <header></header>
 <div class = "body">
  <form name="joinfrm" id="joinfrm" action="joinProc.do" method="post">
  <input type="hidden" id="id_ch" name="id_ch" value="false"/>
  <input type="hidden" id="pass_ch" name="pass_ch" value="false"/>
  <input type="hidden" id="email_ch" name="email_ch" value="false"/>
  <input type="hidden" id="m_tel" name="m_tel" value=""/>
  <div class ="wrapper_table">
   <div class="join_header">
    <p>회원 가입</p>
   </div>
   <div class="join_body">
    <dl>
     <div>
      <dt><label>User ID</label></dt>
      <dd><input id="m_id" name="m_id" type="text" size = "30" maxlength="10" name="m_id" id="m_id" placeholder="아이디"></dd>
     </div>
     <div class='arrow_box' id="id_notice">
        <ul>
      <li><a class="notice" id="info_id1">* 영문 또는, 영문과 숫자의 조합으로 설정해주시기 바랍니다. </a></li>
      <li><a class="notice" id="info_id2">* 5자 이상 12자 이하로 설정 가능합니다.</a></li>
        </ul>
       </div>
     <div>
      <dt><label>PassWord</label></dt>
      <dd><input id="m_pass" name="m_pass" type="password" size = "30" maxlegnth="10" placeholder="비밀번호"></dd>
     </div>
    <div class='arrow_box' id="pass_notice">
        <ul>
      <li><a class = "notice" id="info_pass1">* 영문과 숫자의 조합으로 설정해주시기 바랍니다.</li>
      <li><a class = "notice" id="info_pass2">* 8자 이상으로 설정 가능합니다.</a></li>
        </ul>
       </div>
     <dt><label>PassWord Check</label></dt>
     <dd><input id="m_pass_ch" name="m_pass_ch" type="password" size = "30" maxlength="10" placeholder="비밀번호 확인"></dd>
    <div class='arrow_box' id="pass_ch_notice" style="display:none;">
         <ul>
       <li><a class = "notice" style="color:red;">비밀번호를 확인해 주세요.</a></li>
         </ul>
       </div>
     <dt><label>Name</label></dt>
     <dd><input id="m_name" name="m_name" type="text" size = "30" maxlength="10" placeholder="이름"></dd>
     <dt><label>Birth Date</label></dt>
     <dd><input id="m_date" name="m_date" type="date" min="1930-01-01" max='2010-12-31'></dd>
     <dt><label>Phone Number</label></dt>
     <dd class = "tel"><select id = "m_tel1" name ="tel1"><option selected>010</option>
      <option>011</option>
      <option>016</option>
      <option>017</option>
      <option>019</option>
     </select>
     &nbsp-&nbsp<input id = "m_tel2" name ="m_tel2" type="text" minlength="3" maxlength="4" size="4" required/>
     &nbsp-&nbsp<input id = "m_tel3" name ="m_tel3" type="text" maxlength="4" minlength="4" size="4" required/>
     </dd>
     <dt><label>Gender</label></dt>
     <dd><input id="m_gender" name="m_gender" type="radio" value="남" required></input>&nbsp&nbsp<input name="m_gender" id="m_gender" type="radio" value="여"required></input></dd>
     <dt><label>Email</label></dt>
     <dd><input id="m_email" name="m_email" type="text" placeholder="E-mail"/></dd>
    <div class='arrow_box' id="email_notice" style="display:none;">
         <ul>
       <li><a class = "notice" style="color:red;">이메일 형식이 맞지 않습니다.</a></li>
         </ul>
       </div>
    </dl>
   </div>
   <div class="join_footer">
    <input type="button" value="가입" onclick="doSubmit()">
   </div>
  </div>
  </form>

 </div>
</body>
</html>


  •  table로 작성하려다가 여러 사이트의 회원가입 사이트를 구경하다가 '생활코딩'의 회원가입폼 소스를 뜯어보고 참조해서 만들었기 때문에 table이 아닌 div, dt,dd를 이용하여 만들어 봤습니다. 
  • 여기서 중요한 것은 전달되는 값들의 name값입니다. DB의 테이블의 컬럼값과 변수명을 통일하지 않는다면 나중에 node를 통하여 mysql로 값을 넘겨줄 경우 새로 맵핑해줘야 하는 번거로움이 발생합니다.
  • form에서 전달하는 방법은 post로 해줘야 합니다. get으로 전송할 경우 인젝션에 취약해지기 때문입니다. 또한 통상적으로 값을 입력하고 수정,삭제하는 페이지로의 값 전송에 있어서는 post를 사용하고 단순히 값을 보여주는 페이지, 예로들어 게시판 글보기 페이지 같은 경우는 get을 이용하여 그 글에 대한고유 url을 만들어 줄 수 있기 때문에 get을 사용한다고 합니다.
  • 단순한 html은 아무런 기능은 없으니 바로 css로 넘어가겠습니다.



  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/* http://meyerweb.com/eric/tools/css/reset/
   v2.0 | 20110126
   License: none (public domain)
*/

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 100%;
    font: inherit;
    vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
    display: block;
}
body {
    line-height: 1;
}
ol, ul {
    list-style: none;
}
blockquote, q {
    quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
    content: '';
    content: none;
}
table {
    border-collapse: collapse;
    border-spacing: 0;
}
/*초기화 끝 css 시작*/
.body{
 width: 1000px;
 margin: 0 auto;
}

table .label{
 font-size: 1em;
 color : #aabbcc;
}
table .notice{
 color: blue;
 font-size: 0.7em;
 display : none;
}

.wrapper_table{
 margin: 50px auto;
 box-shadow :0 0 10px #bbb;
 /*border: 1px solid blue;*/
 height: auto;
 text-align: center;
 width: 500px;

}
/*join_header*/
.wrapper_table .join_header{
 background-color: #77b9cb;
 border-bottom: 1px solid #bbb;
 height: 50px;
}

.join_header p{
 float: left;
 font-size: 1.2em;
 font-weight: bold;
 padding: 13px 0px 30px 13px;
}
/*join_body*/
.wrapper_table .join_body{
 border-bottom: 1px solid #bbb;
 height: auto;
 text-align: center;
 padding: 0px 50px 20px 50px;
}

.join_body dt{
 margin-top: 20px;
 height: 20px;
 text-align: left;
}

.join_body dt label{
 font-size: 0.8em;
 color: #aaa;
}

.join_body dd input{
 width: 360px;
 height: 40px;
 padding: 0 20px;
 font-size: 20px;
}

.join_body dd select{
 font-size: 20px;
 width: 115px;
 height: 40px;
}

#m_tel2, #m_tel3{
 width: 110px;
 height: 36px;
 padding : 0;
}

#m_gender{
 width: 100px;
}

/*join_footer*/
.wrapper_table .join_footer{
 height: 50px;
 text-align: center;
}

.join_footer input{
 border: 0px;
 background: #3c9;
 width: 400px;
 height: 40px;
 margin: 5px;
 font-size: 20px;
 color: #ddd;
}

.arrow_box {
 margin-top:20px;
 position: relative;
 padding: 5px;
 background: #88b7d5;
 border: 4px solid #c2e1f5;
 text-align: left;
}
.arrow_box:after, .arrow_box:before {
 bottom: 100%;
 left: 50%;
 border: solid transparent;
 content: " ";
 height: 0;
 width: 0;
 position: absolute;
 pointer-events: none;
}

.arrow_box:after {
 border-color: rgba(136, 183, 213, 0);
 border-bottom-color: #88b7d5;
 border-width: 10px;
 margin-left: -180px;
}
.arrow_box:before {
 border-color: rgba(194, 225, 245, 0);
 border-bottom-color: #c2e1f5;
 border-width: 16px;
 margin-left: -186px;
}

.arrow_box a{
  font-size:0.7em;
}


  • 1~49번 라인은 css 초기화를 위한 문자으로 제일 처음 적어주게 됩니다.
  • css 초기화를 하는 이유는 브라우저마다 padding, margin등의 기본값이 초금씩 다르기 때문입니다. 즉 모든 브라우저에서 디자인으로 보여질수 있도록 하기 위해서 입니다.
  • 다음은 마지막 부분인 Javascript 부분,




  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
function atrim(str){
  return str.replace(/\s/g,'');
}
function blankcheck(el,msg){
 if(el.value==""){
  alert(msg+"를(을) 입력해주세요.");
  el.focus();
  return true;
 }
 if(el.value.length != atrim(el.value).length){
  alert(msg+"에는 공백을 허용하지 않습니다.");
  el.focus();
  return true;
 }
}
function doSubmit() {

 console.log("doSubmit");

 if(blankcheck(joinfrm.m_id,'아이디') || joinfrm.id_ch.value == false) {
  return;
 }

 if(blankcheck(joinfrm.m_pass,'비밀번호') || joinfrm.pass_ch.value == false) {
  return;
 }

 if(blankcheck(joinfrm.m_pass_ch,'비밀번호'))
  return;

 if(blankcheck(joinfrm.m_name,'이름'))
  return;

 if(blankcheck(joinfrm.m_date,'날자'))
  return;

 if(blankcheck(joinfrm.m_tel1,'전화'))
  return;
 if(blankcheck(joinfrm.m_tel2,'전화'))
  return;
 if(blankcheck(joinfrm.m_tel3,'전화'))
  return;
 joinfrm.m_tel.value = joinfrm.m_tel1.value+"-"+joinfrm.m_tel2.value+"-"+joinfrm.m_tel3.value;
 if(blankcheck(joinfrm.m_gender,'성별'))
  return;

 if(blankcheck(joinfrm.m_email,'이메일' || joinfrm.email_ch.value == false))
  return;
 joinfrm.submit();
}

$(document).ready(function() {
 var check_Eng= /[a-z]|[A-Z]/;
 var check_Num= /[0-9]/;
 var check_Num_Eng= /[0-9]|[a-z]|[A-Z]/;
 var check_kor = /([^가-힣ㄱ-ㅎㅏ-ㅣ\x20])/i;
 var check_email = /^[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*\.[a-zA-Z]{2,3}$/i;
 $("#m_id").change(function(){
  joinfrm.id_ch.value = false; //id_ch 히든값 초기화 후 검사 시작
  console.log('1. '+joinfrm.id_ch.value);
  // alert('id값 변경');
  var id = joinfrm.m_id.value;
  var id_flag = false;
  if(id.match(check_Num_Eng) == null || id.match(check_Eng) == null){
  /*if(!check_kor.test(id)){*/
   $("#info_id1").css("color","red");
   // alert('영문 또는 영문,숫자 조합을 사용하여야 합니다.');
   id_flag = true;
  }else{$("#info_id1").css("color","blue");}

  if(id.length<5 || id.length >13){
   $("#info_id2").css("color","red");
   id_flag = true;
  }else{$("#info_id2").css("color","blue");}
  if(id_flag){
   joinfrm.m_id.focus();
   return;
  }
  joinfrm.id_ch.value = true;
  console.log('2. '+joinfrm.id_ch.value);
 });

 $("#m_pass").change(function(){
  joinfrm.pass_ch.value = false;
  // joinfrm.m_pass_ch.value = ""; //비밀번호 변경시 비밀번호 확인 칸 초기화
  var pass = joinfrm.m_pass.value;
  // alert("포커스 아웃  " + pass);
  var pass_flag = false;
  if(pass.match(check_Num_Eng) == null || pass.match(check_Num) == null || pass.match(check_Eng) == null){
   // alert("패스워드 잘못됨");
   $("#info_pass1").css("color","red");
   pass_flag = true;
  }else{$("#info_pass1").css("color","blue");}
  if(pass.length<8){
   $("#info_pass2").css("color","red");
   pass_flag = true;
  }else{$("#info_pass2").css("color","blue");}
  if(pass_flag){
   joinfrm.m_pass.focus();
   return;
  }
  joinfrm.pass_ch.value = true;
  console.log(pass);

 });

 $("#m_pass_ch").change(function() {
   alert("ㅎㅇ");
  joinfrm.pass_ch.value = false;
  if(joinfrm.m_pass_ch.value != joinfrm.m_pass.value){
   alert("ㅎㅇ");
   $("#pass_ch_notice").css("display","block");
   joinfrm.m_pass_ch.focus();
   return;
  }
  $("#pass_ch_notice").css("display","none");
  joinfrm.pass_ch.value = true;
 });

 $("#m_email").change(function(){
  joinfrm.email_ch.value = false;
  if(!joinfrm.m_email.value.match(check_email)){
   $("#email_notice").css("display","block");
   joinfrm.m_email.focus();
   return;
  }
  $("#email_notice").css("display","none");
  joinfrm.email_ch.value = true;
 });
});


  • 1~3번 Line : 공백에 대한 유효성검사를 위해서 만들어 봤습니다. 변수의 공백을 없애고 그 값을 반환합니다.
  • 4~10번 Line : 빈칸에 대한 검사를 하고 atrim함수를 호출하여 공백에대한 유효성 검사도 같이합니다.
  • 16~50번 Line : html 아래 부분의 버튼을 눌렀을 경우 호출하며 위의 유효성 검사 함수를 호출하여 실행합니다. 
  • 52번~ : 아이디, 비밀번호, 이메일에 대한 유효성 검사를 위해서 jquery의 change함수를 이용하여 구현해봤습니다. 이 부분에 대한 유효성은 정규표현식을 이용하였습니다.
완성된 페이지는
이렇습니다.
아이디와 비밀번호를 잘못입력하게 되면 해당되는 경고문구가 빨간색으로 칠해지게 됩니다.
비밀번호와 다시 입력하여 확인하는 경우, 이메일이 형식에 맞지않는경우 해당칸 아래에 경고문구가 생기게 됩니다.



댓글 4개:

  1. 혹시 52~ 부분에서도 유효성을 통과하지 못하면 submit 되지 못하게 할 수는 없을까요?

    답글삭제
    답글
    1. 늦었어요!
      상태값을 바깥쪽에 하나 두어서 change가 이루어질때마다 false로 만들어주고 1번라인부터 적혀진 부분에서 체크를 하고 넘기면 되겠죠?

      삭제
  2. 세개 페이지 다 만들었는데 실행은 어떻게 하나요?..제가 아직 잘 몰라서ㅠㅠ 답변 부탁드립니다..

    답글삭제
    답글
    1. 3개 게시물 다 하셨다는거면 콘솔로 node.js 위치에서 "npm start" 또는 "node ./bin/www" 로 실행하셔서 127.0.0.1:3000/member/join으로 접속하시면됩니다.

      이 게시물의 3개 파일만 작성하셨다면, 그냥 html파일을 여시면 될겁니다.

      삭제