프로젝트 진행 기록/메뉴 메이트 웹 애플리케이션 개발

SignupPage.vue 구성

김쟈워니 2024. 9. 12. 12:13

SignupPage.vue 구성

 

 

1. 템플릿 구성

<template>
    <div class="signup_container">
        <div class="signup_card">

            <div class="signup_appName">
                <span class="signup_appName_first_M">M</span>enu
                <span class="signup_appName_second_M">M</span>ate
            </div>

            <div class="signup_pageTitle">회원가입 페이지</div>

            <form>
                <div class="signup_ID_form signup_form_group">
                    <label for="userID" class="signup_ID_label signup_form_label">아이디:</label>
                    <input type="text" class="signup_ID_input signup_form_input">
                    <button type="button" class="signup_ID_check_button">중복 확인</button>
                </div>
                <div class="signup_ID_check_info signup_info"> <span>사용할 수 없는 아이디입니다 등 알림</span></div>

                <div class="signup_password_form signup_form_group">
                    <label for="userPassword" class="signup_password_label signup_form_label">비밀번호:</label>
                    <input type="password" class="signup_password_input signup_form_input">
                </div>
                <div class="signup_password_rule signup_info"><span>비밀번호는 8자 이상, 특수문자 사용 가능</span></div>
                <div class="signup_password_available signup_info"><span>사용할수 있는, 없는 비밀번호, 비밀번호 규칙을 지켜주세요</span></div>

                <div class="signup_password_check_form signup_form_group">
                    <label for="userPasswordCheck" class="signup_password_check_label signup_form_label">비밀번호
                        확인:</label>
                    <input type="password" class="signup_password_check_input signup_form_input">
                </div>
                <div class="signup_password_check_info signup_info"><span>비밀번호 확인 완료 or not</span></div>

                <div class="signup_userName_form signup_form_group">
                    <label for="userName" class="signup_userName_label signup_form_label">이 름:</label>
                    <input type="text" class="signup_userName_input signup_form_input">
                </div>

                <div class="signup_userPhone_form signup_form_group">
                    <label for="userPhone" class="signup_userPhone_label signup_form_label">전화번호:</label>
                    <select class="signup_userPhone_areaNum signup_form_input">
                        <option value="" disabled>지역번호</option>
                        <option v-for="area in phoneAreas" :key="area" :value="area">{{ area }}</option>
                    </select>
                    <span>-</span>
                    <input type="text" class="signup_userPhone_midNum signup_form_input" placeholder="가운데 번호"
                        maxlenght="4">
                    <span>-</span>
                    <input type="text" class="signup_userPhone_endNum signup_form_input" placeholder="끝자리 번호"
                        maxlength="4">
                </div>

                <div class="signup_userBirth_form signup_form_group">
                    <label for="userBirth" class="signup_userBirth_label signup_form_label">생년월일:</label>
                    <input type="date" class="signup_userBirth_input signup_form_input">
                </div>

                <div class="signup_userpostcode_form signup_form_group">
                    <label for="userPostcode" class="signup_userPostcode_label signup_form_label">우편번호:</label>
                    <input type="text" class="signup_userPostcode_input signup_form_input" placeholder="우편번호" readonly>
                    <button type="button" class="signup_find_userAddress_button">주소 검색</button>
                </div>

                <div class="signup_useraddress_form signup_form_group">
                    <label for="userAddress" class="signup_userAddress_label signup_form_label">주소:</label>
                    <input type="text" class="signup_userAddress_input signup_form_input" placeholder="주소" readonly>
                </div>

                <div class="signup_useraddress_detail_form signup_form_group">
                    <label for="userAddressDetail"
                        class="signup_userAddressDetail_label signup_form_label">상세주소:</label>
                    <input type="text" placeholder="상세주소" class="signup_userAddressDetail_input signup_form_input">
                </div>

                <hr>

                <button type="submit" class="signup_submit_button">회원가입</button>

            </form>

        </div>
    </div>
</template>

각 요소들을 만든 템플릿

  • input 안에 있는 내용들을 백엔드로 보내기 위해서 <form> 태그 내부에 백엔드로 전송시킬 요소들을 넣었음
  • 아직 form 에 action과 methods가 아직 작성되지 않은 이유는 axios 를 이용하여 post 방식으로 백엔드로 전송할 것이구 이는 해당페이지의 기능 구현이 완료된 후 백엔드를 작성하면서 작성할 예정 

 

2. signuppage.vue 스타일링 구성

<style>
.signup_container {
    display: flex;
    justify-content: center;
    height: 82vh;
    background-color: #f2f4f7;
}

.signup_card {
    background-color: white;
    width: 800px;
    margin: 20px;
    border-radius: 10px;
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

.signup_appName {
    font-size: 28px;
    margin-bottom: 10px;
}

.signup_appName_first_M,
.signup_appName_second_M {
    color: crimson;
}

.signup_pageTitle {
    font-size: 30px;
    font-weight: bold;
    margin-bottom: 20px;
}

/* 각 요소 전체 틀 우선 */
.signup_form_group {
    display: flex;
    align-items: center;
}

.signup_form_label {
    text-align: center;
    width: 150px;
    font-size: 20px;
    color: #333;
    margin-left: 10px
}

.signup_form_input {
    font-family: '명품굴림';
    padding: 10px;
    font-size: 18px;
    font-weight: bold;
    border: 1px solid #ddd;
    border-radius: 5px;
    outline: none;
    margin-right: 20px;

}

.signup_info {
    margin-top: 3px;
    margin-bottom: 3px;
    margin-left: 160px;
    text-align: left;
}

/* 세부 조절 */

.signup_userName_form,
.signup_userPhone_form,
.signup_userBirth_form,
.signup_userpostcode_form,
.signup_useraddress_form,
.signup_useraddress_detail_form {
    margin-bottom: 20px;
}

.signup_ID_input {
    width: 300px;
    margin-right: 50px;
}

.signup_password_input,
.signup_password_check_input,
.signup_userName_input {
    width: 400px;
}

.signup_userPhone_areaNum {
    margin-right: 10px;
}

.signup_userPhone_midNum,
.signup_userPhone_endNum {
    margin: 10px;
}

.signup_userBirth_input {
    text-align: center;
    width: 250px;
}

.signup_userPostcode_input {
    width: 250px;
}
.signup_userAddress_input,
.signup_userAddressDetail_input{
    width: 470px;
}


.signup_ID_check_button,
.signup_find_userAddress_button{
    background-color: #007bff;
    color: white;
    margin-right: 10px;
    padding: 7px 0;
    font-size: 20px;
    font-weight: bold;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    width: 200px;
    transition: background-color 0.3s;
}

.signup_submit_button {
    background-color: crimson;
    color: white;
    padding: 15px 0;
    margin-bottom:10px;
    font-size: 25px;
    font-weight: bold;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    width: 200px;
    transition: background-color 0.3s;
}

.signup_ID_check_button:hover,
.signup_find_userAddress_button:hover
{
    background-color: #0056b3;

}


.signup_submit_button:hover {
    background-color:red;

}


hr {
    border: none; /* 기본 테두리 제거 */
    border-top: 1px solid #ddd; /* 연한 회색 선 추가 */
    margin: 20px 0; /* 위아래 간격 추가 */
}

SignupPage.vue CSS 정리

  1. 전체 레이아웃 설정
    • .signup_container:
      • 화면 중앙 정렬을 위해 display: flex, justify-content: center 설정.
      • 화면 높이의 82%를 사용하여 페이지가 중간에 위치하도록 height: 82vh 설정.
      • 연한 회색 배경을 위해 background-color: #f2f4f7 적용.
  2. 카드 레이아웃
    • .signup_card:
      • 흰색 배경과 내부 여백을 위해 background-color: white, margin: 20px 설정.
      • 모서리를 둥글게 하기 위해 border-radius: 10px 적용.
      • 부드러운 그림자 효과를 위해 box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1) 적용.
      • 카드의 고정 너비를 설정하기 위해 width: 800px 설정.
  3. 애플리케이션 이름과 제목
    • .signup_appName:
      • 애플리케이션 이름의 크기를 font-size: 28px로 설정.
      • 아래쪽 여백을 추가하기 위해 margin-bottom: 10px 적용.
    • .signup_appName_first_M, .signup_appName_second_M:
      • 첫 번째와 두 번째 "M" 글자를 강조하기 위해 color: crimson 설정.
    • .signup_pageTitle:
      • 페이지 제목의 크기를 font-size: 30px로 설정하고, 굵게 표시하기 위해 font-weight: bold 적용.
      • 제목 아래 여백을 추가하기 위해 margin-bottom: 20px 적용.
  4. 입력 필드 스타일
    • .signup_form_group:
      • 레이블과 입력 필드를 수평으로 정렬하기 위해 display: flex, align-items: center 설정.
    • .signup_form_label:
      • 레이블의 고정 너비와 필드 사이의 여백을 설정하기 위해 width: 150px, margin-left: 10px 적용.
      • 레이블 텍스트 크기를 font-size: 20px로 설정하고, 색상을 color: #333으로 적용.
    • .signup_form_input:
      • 입력 필드에 충분한 여백을 주기 위해 padding: 10px 설정.
      • 입력 필드의 크기와 텍스트 크기를 font-size: 18px, font-weight: bold로 설정.
      • 테두리를 border: 1px solid #ddd로 설정하고 둥근 모서리를 위해 border-radius: 5px 적용.
  5. 유효성 검사 메시지 스타일
    • .signup_info:
      • 유효성 검사 메시지를 왼쪽 정렬하고, 입력 필드와 일치하게 정렬하기 위해 margin-left: 160px, text-align: left 적용.
      • 위아래 간격을 주기 위해 margin-top: 3px, margin-bottom: 3px 설정.
  6. 개별 입력 필드 스타일
    • .signup_ID_input:
      • 아이디 입력 필드의 너비를 width: 300px, 오른쪽 여백을 margin-right: 50px로 설정.
    • .signup_password_input, .signup_password_check_input, .signup_userName_input:
      • 비밀번호 및 이름 입력 필드의 너비를 각각 width: 400px로 설정.
    • .signup_userPhone_areaNum:
      • 전화번호 앞자리 선택 필드에 오른쪽 여백을 margin-right: 10px으로 설정.
    • .signup_userPhone_midNum, .signup_userPhone_endNum:
      • 전화번호 중간 및 끝자리 입력 필드에 여백을 margin: 10px으로 설정.
    • .signup_userBirth_input:
      • 생년월일 입력 필드를 가운데 정렬하고, 너비를 width: 250px으로 설정.
    • .signup_userPostcode_input:
      • 우편번호 입력 필드의 너비를 width: 250px으로 설정.
    • .signup_userAddress_input, .signup_userAddressDetail_input:
      • 주소 및 상세 주소 입력 필드의 너비를 각각 width: 470px으로 설정.
  7. 버튼 스타일
    • .signup_ID_check_button, .signup_find_userAddress_button:
      • 버튼의 배경색을 background-color: #007bff, 글자색을 흰색으로 설정.
      • 버튼 크기를 적절하게 조정하기 위해 padding: 7px 0, width: 200px 설정.
      • 버튼의 둥근 모서리 및 클릭 시 변화 효과를 위해 border-radius: 5px, transition: background-color 0.3s 적용.
    • .signup_submit_button:
      • 제출 버튼의 배경색을 background-color: crimson, 글자색을 흰색으로 설정.
      • 충분한 여백과 큰 텍스트 크기를 위해 padding: 15px 0, font-size: 25px 설정.
      • 클릭 시 배경색이 진해지도록 background-color: red로 변경되는 호버 효과 적용.
  8. 구분선 스타일
    • hr:
      • 기본 테두리를 제거하고, 연한 회색 선을 추가하기 위해 border: none, border-top: 1px solid #ddd 설정.
      • 구분선 위아래 간격을 margin: 20px 0으로 설정.

 

3. SignupPage.vue 기능 구현

 

1. 각 입력 요소에 v-model 구현 및 v-model 에 맞는 데이터함에 데이터 만들기

 

각 요소에 v-model 추가

 

아이디 입력 input 

<input type="text" class="signup_ID_input signup_form_input" v-model="signup_form.userID">

 

비밀번호 입력 input

<input type="password" class="signup_password_input signup_form_input" v-model="signup_form.userPassword">

 

비밀번호 확인 입력 input

<input type="password" class="signup_password_check_input signup_form_input" v-model="signup_form.userPasswordCheck">

이름 입력 input

<input type="text" class="signup_userName_input signup_form_input" v-model="signup_form.userName">

 

전화번호 앞자리 input

<select class="signup_userPhone_areaNum signup_form_input" v-model="signup_form.userPhone_areaNum">

 

전화번호 중간자리 input

<input type="text" class="signup_userPhone_midNum signup_form_input" placeholder="가운데 번호"
 maxlenght="4" v-model="signup_form.userPhone_midNum">

 

전화번호 마지막자리 input

<input type="text" class="signup_userPhone_endNum signup_form_input" placeholder="끝자리 번호"
maxlength="4" v-model="signup_form.userPhone_endNum">


생년월일 input

 <input type="date" class="signup_userBirth_input signup_form_input" v-model="signup_form.userBirth">

우편번호 input

  <input type="text" class="signup_userAddress_input signup_form_input" placeholder="주소" readonly
v-model="signup_form.userPostcode">

주소 input

<input type="text" class="signup_userAddress_input signup_form_input" placeholder="주소" readonly
 v-model="signup_form.userAddress">

상세 주소 input

<input type="text" placeholder="상세주소" class="signup_userAddressDetail_input signup_form_input"
v-model="signup_form.userAddressDetail">


v-model로 입력받은 데이터를 담을 데이터함 추가 

<script>
export default {
    name: 'SignupPage',
    data() {
        return {
            phoneAreas: ['010', '02', '031', '032', '033', '041', '042', '043', '044', '051', '052', '053', '054', '055', '061', '062', '063', '064'],
            // signup 페이지에서 입력받은 요소를 집어넣을 데이터 함 추가
            signup_form: {
                userID: '',
                userPassword: '',
                userPasswordCheck: '',
                userName:'',
                userPhone_areaNum: '',
                userPhone_midNum: '',
                userPhone_endNum:'',
                userBirth:'',
                userPostcode:'',
                userAddress:'',
                userAddressDetail:'',
            }
        }
    }

 

2. 주소 검색 버튼 클릭시 daumpostcode API 를 호출

1. index.html 에 들어가서 <body> 태그 최하단 </body> 태그 위에 다음주소찾기api script 추가

  <script src="//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"></script>

 

 

2. SignupPage.vue 로 돌아가 주소검색 버튼에 이벤트 추가

<button type="button" class="signup_find_userAddress_button" @click="openDaumPostCodeAPI">주소 검색</button>

3. 해당 이벤트에 맞는 methods 작성

 기존 JSP 를 이용하여 daumpostcode API 를 호출할때는

    new daum.Postcode({
        oncomplete: function(data) {
            // 팝업에서 검색결과 항목을 클릭했을때 실행할 코드를 작성하는 부분입니다.
            // 예제를 참고하여 다양한 활용법을 확인해 보세요.
        }
    }).open();

 

이것을 기본 틀로 하여 작성하였음.

 

Failed to compile with 1 error 오후 1:23:30
[eslint] C:\Users\kimjw\Desktop\프로젝트 연\frontend_p\src\components\Home\innerComponents\SignupPage.vue 114:17 error 'daum' is not defined no-undef
✖ 1 problem (1 error, 0 warnings)
You may use special comments to disable some warnings.
Use // eslint-disable-next-line to ignore the next line.
Use /* eslint-disable */ to ignore all warnings in a file.
ERROR in [eslint]
C:\Users\kimjw\Desktop\프로젝트 연습\frontend_p\src\components\Home\innerComponents\SignupPage.vue 114:17 error 'daum' is not defined no-undef ✖ 1 problem (1 error, 0 warnings) webpack compiled with 1 error

 

하지만 작성중에 daum 객체가 정의되지 않았다고 하는 오류가 발생

(Vue는 SPA 로 index.html 과 vue 파일로 이루어져있으나 컴포넌트 작성단계에서는 두가지가 구분되어 index.html의 script태그를 불러오지 못함으로써 발생하는 것으로 보임)


해결방법 1 ESLint에 글로벌 객체로 daum 명시하기

.eslintrc.js 또는 .eslintrc.json 파일에서 ESLint 설정을 수정하여 daum을 글로벌 객체로 인식

.eslintrc.js

module.exports = {
  env: {
    browser: true,
    node: true,
  },
  globals: {
    daum: 'readonly', // daum 객체가 전역에서 읽기 전용임을 ESLint에 알림
  },
  // 다른 설정들...
};

.eslintrc.json 

{
  "env": {
    "browser": true,
    "node": true
  },
  "globals": {
    "daum": "readonly"
  }
}

 

(vuecli 로 프로젝트 작성하면 package.json 내부 eslintConfig 객체에 "globals" 객체를 만들고 "daum": "readonly"를 추가 하면 됨_본인은 vueCLI로 프로젝트를 생성)

 

 

2. 특정 라인에서만 ESLint 규칙 무시하기

//eslint-disable-next-line 를 사용하여

   // eslint-disable-next-line
   new daum.Postcode({
        oncomplete: function(data) {
            // 팝업에서 검색결과 항목을 클릭했을때 실행할 코드를 작성하는 부분입니다.
            // 예제를 참고하여 다양한 활용법을 확인해 보세요.
        }
    }).open();

3. api가 로드 된경우와 로드되지 않은 경우로 구분하여 작성

if (window.daum && window.daum.Postcode) {
	new window.daum.Postcode({
    oncomplete:(data)->{
   
   //
     }
    }).open();
   } else {
   alert('daum postcode api 로드 불가.');
    }
   }

 

 

+ vue 3 에서는 function 키워드 되신 람다식 표현을 씀

이는 function 키워드는 자신만 this 바인딩을 하지만, 람다식 표현은 부모 스코프의 this를 상속할 수 있기 떄문

 

본인은 3번으로 기능 구현하였음

 methods: {
        openDaumPostCodeAPI() {
            if (window.daum && window.daum.Postcode) {
                new window.daum.Postcode({
                    oncomplete: (data) => {
                        this.signup_form.userPostcode = data.zonecode;
                        this.signup_form.userAddress = data.roadAddress;
                        this.signup_form.userAddressDetail = '';
                    }
                }).open();
            } else {
                alert('Daum Postcode API를 로드할 수 없습니다.');
            }
        },
    },
}

3. 각 input에 입력요소 유효성 검사 만들기