21.03.03 lamplight서비스 프로젝트(글쓰기,상세페이지,로그인 ~ 회원가입까지)
2021. 3. 3. 22:59ㆍVue.js/Spring & Vue APP 프로젝트(프론트엔드)
#NOTE
<post 전송방식>
1.form 방식
일반 form 형식
2.axios json 방식
json 형식
:to와 to의 차이??
:이 있으면 자바스크립트 사용 가능
ex)
to="article/list"
:to="'article/list?boardId' + article.boardId"
protected _handleResponse(axiosResponse:AxiosResponse) : AxiosResponse {
// 로그인 정보 체크
// axiosResponse?.data?.resultCode == "F-A" || axiosResponse?.data?.resultCode == "F-B" (초보 버전)
// axiosResponse?.data?.resultCode == "F-A" => 로그인 정보가 아예 없는 경우
// axiosResponse?.data?.resultCode == "F-B" => 로그인 정보가 틀린 경우
// axiosResponse?.data?.resultCode == "F-A" || axiosResponse?.data?.resultCode == "F-B" (초보 버전)
//["F-A", "F-B"].includes(axiosResponse?.data?.resultCode) (고급 버전)
/* 로그인 정보 체크 후 로그인 화면으로 이동 */
if (["F-A", "F-B"].includes(axiosResponse?.data?.resultCode)) {
alert('로그인 후 이용해주세요.');
location.replace('/member/login');
}
return axiosResponse;
}
<컴포넌트>
현재 앱 컴포넌트와 페이지별 컴포넌트로 구성
페이지 컴포넌트는 현재 라우터(주소)에 의해 자동적으로 선택되고 있음
<state: 상태>
페이지 글과 같은 상태는 전역적으로 필요하지 않음
하지만 로그인 정보의 경우 전역적으로 필요함
이를 위해 전역상태를 구축해야함
#주요소스코드
<main.ts>
import { createApp, reactive, computed } from 'vue'
import { createRouter, createWebHistory } from 'vue-router'
// 앱 컴포넌트 불러오기
import App from './App.vue'
// 전역 CSS 불러오기
import './index.css'
// 전역 컴포넌트 불러오기
import * as Util from './utils/'; // utils파일로 부터 가져오는 모든 것(*)은 Util로 치환
import TitleBar from './components/TitleBar.vue';
import FormRow from './components/FormRow.vue';
// 각 페이지 불러오기
import HomeMainPage from './pages/HomeMainPage.vue'
import ArticleListPage from './pages/ArticleListPage.vue'
import ArticleWritePage from './pages/ArticleWritePage.vue'
import ArticleDetailPage from './pages/ArticleDetailPage.vue'
import MemberLoginPage from './pages/MemberLoginPage.vue'
import MemberJoinPage from './pages/MemberJoinPage.vue'
// 전역state 만들기
/// localStorage에서 로그인 정보 가져오기
const authKey = localStorage.getItem("authKey")
const loginedMemberId = Util.toIntOrNull(localStorage.getItem("loginedMemberId"))
const loginedMemberName = localStorage.getItem("loginedMemberName")
const loginedMemberNickname = localStorage.getItem("loginedMemberNickname")
/*state => 상태
페이지 글과 같은 state는 전역적으로 필요하지 않음
하지만 로그인 정보의 경우 전역적으로 필요함
이를 위해 전역state(=> globalShare)를 구축해야함*/
const globalShare:any = reactive({
//loginedMember:{}, //loginedMember:{}는 비어있는 상태
//로그인 정보 채우기
loginedMember:{
authKey,
id:loginedMemberId,
name:loginedMemberName,
nickname:loginedMemberNickname,
},
//globalShare.loginedMember가 비어있지 않는지를 computed로 자동 체크
//비어있지 않다면(===false) isLogined
//isLogined: computed(() => Util.isEmptyObject(globalShare.loginedMember) === false)
isLogined: computed(() => globalShare.loginedMember.id !== null ),
//로그아웃
logout: () => {
localStorage.removeItem("authKey");
localStorage.removeItem("loginedMemberId");
localStorage.removeItem("loginedMemberName");
localStorage.removeItem("loginedMemberNickname");
location.replace('/member/login');
}
});
/*테스트용
setTimeout(() => {
globalShare.loginedMember.id = 1;
}, 5000);
*/
// MainApi 불러오기
import { MainApi } from './apis/'
// MainApi 객체 생성
const mainApi = new MainApi();
// 라우팅 정보 설정(구성)
const routes = [
{
path: '/',
component: HomeMainPage
},
{
path: '/article/list',
component: ArticleListPage,
//주소에 바로 접근하지 않게끔하고
//props로 들어오는 경로로 접근하도록??
props: (route:any) => ({ boardId: Util.toIntOrUnd(route.query.boardId), globalShare })
},
{
path: '/article/write',
component: ArticleWritePage,
props: (route:any) => ({ boardId: Util.toIntOrUnd(route.query.boardId), globalShare })
},
{
path: '/article/detail',
component: ArticleDetailPage,
props: (route:any) => ({ id: Util.toIntOrUnd(route.query.id), globalShare })
},
{
path: '/member/login',
component: MemberLoginPage,
props: (route:any) => ({globalShare})
},
{
path: '/member/join',
component: MemberJoinPage,
props: (route:any) => ({globalShare})
}
];
// 라우팅 정보를 가져오는 라우터 생성
const router = createRouter({
//Provide the history implementation to use. We are using the hash history for simplicity here.
history: createWebHistory(),
//routes : routes 이름이 똑같으면 아래처럼 축약 가능
routes
});
//앱 생성
//createApp(App).mount('#app') 이것을 풀어보면 아래와 같음
const app = createApp(App, {
globalShare
});
//앱에 전역 라이브러리 등록
app.config.globalProperties.$mainApi = mainApi;
app.config.globalProperties.$router = router;
//앱에 전역 컴포넌트 적용
//모든 곳에서 컴포넌트를 불러올수 있게 해줌
app.component('TitleBar',TitleBar)
app.component('FormRow',FormRow)
//앱에 라우터 적용
app.use(router)
//앱 표시
app.mount('#app');
<apis/index.ts>
import axios, { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
import {IArticle} from '../types'
// API 원형
abstract class HttpClient {
protected readonly instance: AxiosInstance;
public constructor(instance: AxiosInstance) {
this.instance = instance;
this._initializeRequestInterceptor();
this._initializeResponseInterceptor();
}
private _initializeRequestInterceptor() {
this.instance.interceptors.request.use(
this._handleRequest,
this._handleError,
);
};
private _initializeResponseInterceptor() {
this.instance.interceptors.response.use(
this._handleResponse,
this._handleError,
);
};
protected _handleRequest(config:AxiosRequestConfig) : AxiosRequestConfig {
return config;
}
protected _handleResponse(axiosResponse:AxiosResponse) : AxiosResponse {
return axiosResponse;
}
protected _handleError(error: AxiosError) {
if (error.response) {
// 요청이 이루어졌으며 서버가 2xx의 범위를 벗어나는 상태 코드로 응답했습니다.
alert('요청을 처리하는 중에 오류가 발생하였습니다.');
}
else if (error.request) {
// 요청이 이루어 졌으나 응답을 받지 못했습니다.
// `error.request`는 브라우저의 XMLHttpRequest 인스턴스 또는
// Node.js의 http.ClientRequest 인스턴스입니다.
alert('서버 또는 네트워크의 상태가 좋지 않습니다.');
}
else {
// 오류를 발생시킨 요청을 설정하는 중에 문제가 발생했습니다.
console.log('Error', error.message);
}
return Promise.reject(error);
};
// POST전송으로 전송하기 위한 로직
public postByForm<T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R> {
const params = new URLSearchParams();
for ( let key in data ) {
params.append(key, data[key]);
}
config = {} as AxiosRequestConfig;
config.headers = {
'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Accept': '*/*'
};
return this.instance.post(url, params, config);
}
}
// 응답타입1
interface Base__IResponseBodyType1 {
resultCode:string;
msg:string;
fail:boolean;
success:boolean;
}
// /usr/article/list 의 응답 타입
export interface MainApi__article_list__IResponseBody extends Base__IResponseBodyType1 {
body:{
articles: IArticle[]
};
}
// /usr/article/detail 의 응답 타입
export interface MainApi__article_detail__IResponseBody extends Base__IResponseBodyType1 {
body:{
article: IArticle
};
}
// /usr/article/doAdd 의 응답 타입
export interface MainApi__article_doWrite__IResponseBody extends Base__IResponseBodyType1 {
body:{
id: number
};
}
// /usr/member/authKey 의 응답 타입
export interface MainApi__member_authKey__IResponseBody extends Base__IResponseBodyType1 {
body:{
authKey : string,
id : number,
name : string,
nickname : string
};
}
// /usr/member/doJoin 의 응답 타입
export interface MainApi__member_doJoin__IResponseBody extends Base__IResponseBodyType1 {
body:{
id: number
};
}
// http://localhost:8024/usr/ 와의 통신장치
export class MainApi extends HttpClient {
public constructor() {
super(
axios.create({
baseURL:'http://localhost:8024/usr/',
})
);
}
protected _handleRequest(config:AxiosRequestConfig) {
config.params = {};
config.params.authKey = localStorage.getItem("authKey");
return config;
};
protected _handleResponse(axiosResponse:AxiosResponse) : AxiosResponse {
// 로그인 정보 체크
// axiosResponse?.data?.resultCode == "F-A" || axiosResponse?.data?.resultCode == "F-B" (초보 버전)
// axiosResponse?.data?.resultCode == "F-A" => 로그인 정보가 아예 없는 경우
// axiosResponse?.data?.resultCode == "F-B" => 로그인 정보가 틀린 경우
// axiosResponse?.data?.resultCode == "F-A" || axiosResponse?.data?.resultCode == "F-B" (초보 버전)
//["F-A", "F-B"].includes(axiosResponse?.data?.resultCode) (고급 버전)
/* 로그인 정보 체크 후 로그인 화면으로 이동 */
if (["F-A", "F-B"].includes(axiosResponse?.data?.resultCode)) {
alert('로그인 후 이용해주세요.');
//비정상 로그인인 경우 localStorage 초기화
localStorage.removeItem("authKey");
localStorage.removeItem("loginedMemberId");
localStorage.removeItem("loginedMemberName");
localStorage.removeItem("loginedMemberNickname");
location.replace('/member/login');
}
return axiosResponse;
}
// http://localhost:8024/usr/article/list?boardId=? 를 요청하고 응답을 받아오는 함수
public article_list(boardId: number) {
return this.instance.get<MainApi__article_list__IResponseBody>(`/article/list?boardId=${boardId}`);
}
// http://localhost:8024/usr/detail/id=? 를 요청하고 응답을 받아오는 함수
public article_detail(id: number) {
return this.instance.get<MainApi__article_detail__IResponseBody>(`/article/detail?id=${id}`);
}
// http://localhost:8024/usr/article/doAdd/boardId=?&title=?&body=? 를 요청하고 응답을 받아오는 함수
// postByForm: post 전송을 스프링이 이해할 수 있는 form형식으로 전송시켜주는 함수?
public article_doWrite(boardId:number, title: string, body: string) {
return this.postByForm<MainApi__article_doWrite__IResponseBody>(
`/article/doAdd`, {
boardId,
title,
body
}
);
}
// http://localhost:8024/usr/member/authKey/loginId=?&loginPw=? 를 요청하고 응답을 받아오는 함수
// postByForm: post 전송을 스프링이 이해할 수 있는 form형식으로 전송시켜주는 함수?
public member_authKey(loginId: string, loginPw: string) {
return this.instance.get<MainApi__member_authKey__IResponseBody>(`/member/authKey?loginId=${loginId}&loginPw=${loginPw}`);
}
// http://localhost:8024/usr/member/doJoin/loginId=?&loginPw=?...... 를 요청하고 응답을 받아오는 함수
public member_doJoin(loginId:string, loginPw:string, name:string, nickname:string, cellphoneNo:string, email:string) {
return this.postByForm<MainApi__member_doJoin__IResponseBody>(
`/member/doJoin`, {
loginId,
loginPw,
name,
nickname,
cellphoneNo,
email
}
);
}
}
<App.vue>
<!-- vue를 하나의 jsp라고 생각하면 됨 -->
<template>
<header class="header-bar h-20 bg-black text-white">
<div class="container mx-auto flex h-full">
<!-- router-link는 a와 같다고 보면 됨 -->
<!-- to는 href -->
<router-link to="/" class="h-full flex items-center px-2">
<img class="block w-10" src="./assets/logo.png" alt="">
</router-link>
<div class="flex-grow"></div>
<nav class="header-bar__menu-box-1 overflow-x-auto">
<ul class="flex h-full">
<li>
<router-link to="/" class="h-full flex items-center font-bold px-4 hover:bg-white hover:text-black whitespace-nowrap">
홈
</router-link>
</li>
<li v-if="globalShare.isLogined == false">
<router-link to="/member/login" class="h-full flex items-center font-bold px-4 hover:bg-white hover:text-black whitespace-nowrap">
로그인
</router-link>
</li>
<li v-if="globalShare.isLogined == false">
<router-link to="/member/join" class="h-full flex items-center font-bold px-4 hover:bg-white hover:text-black whitespace-nowrap">
회원가입
</router-link>
</li>
<li v-if="globalShare.isLogined">
<a v-on:click="globalShare.logout" class="cursor-pointer h-full flex items-center font-bold px-4 hover:bg-white hover:text-black whitespace-nowrap">
로그아웃
</a>
</li>
<li v-if="globalShare.isLogined">
<router-link to="/article/write" class="h-full flex items-center font-bold px-4 hover:bg-white hover:text-black whitespace-nowrap">
글쓰기
</router-link>
</li>
<li>
<router-link to="/article/list?boardId=1" class="h-full flex items-center font-bold px-4 hover:bg-white hover:text-black whitespace-nowrap">
공지사항 게시판
</router-link>
</li>
<li>
<router-link to="/article/list?boardId=2" class="h-full flex items-center font-bold px-4 hover:bg-white hover:text-black whitespace-nowrap">
자유게시판
</router-link>
</li>
</ul>
</nav>
</div>
</header>
<main>
<!-- 이것을 해주어야 다른 페이지를 불러올 수 있음 -->
<router-view></router-view>
</main>
</template>
<script lang="ts">
import { defineComponent, computed } from 'vue'
export default defineComponent({
name: 'App',
props: {
globalShare: {
type: Object,
required: true
},
},
setup() {
}
})
</script>
<style lang="postcss">
.btn-type-1 {
@apply py-2 px-4 text-white transition ease-in duration-200 text-center text-base font-semibold shadow-md focus:outline-none focus:ring-2 focus:ring-offset-2 rounded-lg cursor-pointer;
}
.btn-primary {
@apply py-2 px-4 bg-blue-600 hover:bg-blue-700 focus:ring-blue-500 focus:ring-offset-blue-200 btn-type-1;
}
.btn-secondary {
@apply py-2 px-4 bg-gray-600 hover:bg-gray-700 focus:ring-gray-500 focus:ring-offset-gray-200 btn-type-1;
}
.btn-success {
@apply py-2 px-4 bg-green-600 hover:bg-green-700 focus:ring-green-500 focus:ring-offset-green-200 btn-type-1;
}
.btn-danger {
@apply py-2 px-4 bg-red-600 hover:bg-red-700 focus:ring-red-500 focus:ring-offset-red-200 btn-type-1;
}
.btn-warning {
@apply py-2 px-4 bg-yellow-600 hover:bg-yellow-700 focus:ring-yellow-500 focus:ring-offset-yellow-200 btn-type-1;
}
.btn-info {
@apply py-2 px-4 bg-purple-600 hover:bg-purple-700 focus:ring-purple-500 focus:ring-offset-purple-200 btn-type-1;
}
.btn-link {
@apply underline text-blue-500 hover:text-red-500 cursor-pointer;
}
/* css 선택자 */
/* .btns 자식들 중에 class로 'btn-'를 갖고 있는 엘리먼트의 다음 엘리먼트 */
.btns > [class*="btn-"] + [class*="btn-"] {
margin-left: theme('spacing.2');
}
</style>
<ArticleWritePage.vue>
<template>
<TitleBar>글쓰기</TitleBar>
<section class="section section-article-write-form-box px-2">
<div class="container mx-auto">
<div class="px-6 py-6 bg-white rounded-lg shadow-md">
<form v-if="globalShare.isLogined" v-on:submit.prevent="checkAndWriteArticle">
<FormRow title="게시판">
<select class="form-row-select" ref="newArticleBoardIdElRef">
<option value="1">NOTICE</option>
<option value="2">FREE</option>
</select>
</FormRow>
<FormRow title="제목">
<input ref="newArticleTitleElRef" class="form-row-input" type="text" placeholder="제목을 입력해주세요.">
</FormRow>
<FormRow title="내용">
<textarea ref="newArticleBodyElRef" class="form-row-input" placeholder="내용을 입력해주세요."></textarea>
</FormRow>
<FormRow title="작성">
<div class="btns">
<input type="submit" value="작성" class="btn-primary" />
</div>
</FormRow>
</form>
<div v-else>
<router-link class="btn-link" to="/member/login">로그인</router-link> 후 이용해주세요.
</div>
</div>
</div>
</section>
</template>
<script lang="ts">
import { defineComponent, reactive, ref, getCurrentInstance, onMounted } from 'vue'
import { MainApi } from '../apis/'
import { Router } from 'vue-router'
export default defineComponent({
name: 'ArticleWritePage',
props: {
globalShare: {
type: Object,
required: true
},
boardId: {
type: Number,
required: true,
default:1
}
},
setup(props){
const router:Router = getCurrentInstance()?.appContext.config.globalProperties.$router;
const mainApi:MainApi = getCurrentInstance()?.appContext.config.globalProperties.$mainApi;
const newArticleBoardIdElRef = ref<HTMLInputElement>();
const newArticleTitleElRef = ref<HTMLInputElement>();
const newArticleBodyElRef = ref<HTMLInputElement>();
//boardId 파라미터 값에 따라 게시판 선택 옵션 값(newArticleBoardIdElRef.value.value)이 바뀜
onMounted(() => {
if(newArticleBoardIdElRef.value == null){
return;
}
newArticleBoardIdElRef.value.value = props.boardId + "";
});
/* 공백 체크 */
function checkAndWriteArticle(){
if(newArticleBoardIdElRef.value == null){
return;
}
const newArticleBoardIdEl = newArticleBoardIdElRef.value;
//일반적으로 안해도 되지만 typescript에서는 해야됨
if(newArticleTitleElRef.value == null){
return;
}
const newArticleTitleEl = newArticleTitleElRef.value;
newArticleTitleEl.value = newArticleTitleEl.value.trim();
if(newArticleTitleEl.value.length == 0){
alert('제목을 입력해 주세요.')
newArticleTitleEl.focus();
return;
}
if(newArticleBodyElRef.value == null){
return;
}
const newArticleBodyEl = newArticleBodyElRef.value;
newArticleBodyEl.value = newArticleBodyEl.value.trim();
if(newArticleBodyEl.value.length == 0){
alert('내용을 입력해 주세요.')
newArticleBodyEl.focus();
return;
}
// 글작성 함수로 보내기
writeArticle(parseInt(newArticleBoardIdEl.value), newArticleTitleEl.value, newArticleBodyEl.value);
}
//typescript에서는 title:string, body:string 이런식으로 type을 적어주어야 한다
function writeArticle(boardId:number, title:string, body:string){
mainApi.article_doWrite(boardId, title, body)
.then(axiosResponse => {
alert(axiosResponse.data.msg);
// 로그인이 fail 상태이면 리턴
if ( axiosResponse.data.fail ) {
return;
}
//authKey가 있는 상태에서 가능
const newArticleId = axiosResponse.data.body.id;
//alert(newArticleId + "번 게시물 등록 완료!!");
router.replace("detail?id=" + newArticleId);
});
}
return{
newArticleBoardIdElRef,
newArticleTitleElRef,
newArticleBodyElRef,
checkAndWriteArticle
}
}
})
</script>
<style scoped>
</style>
<MemberLoginPage.vue>
<template>
<TitleBar>로그인</TitleBar>
<section class="section section-member-login-form px-2">
<div class="container mx-auto">
<div class="px-6 py-6 bg-white rounded-lg shadow-md">
<form v-if="globalShare.isLogined == false" v-on:submit.prevent="checkAndLogin">
<FormRow title="로그인아이디">
<input ref="loginIdElRef" class="form-row-input" type="text" placeholder="아이디를 입력해주세요.">
</FormRow>
<FormRow title="로그인비밀번호">
<input ref="loginPwElRef" class="form-row-input" type="password" placeholder="로그인비밀번호를 입력해주세요.">
</FormRow>
<FormRow title="로그인">
<div class="btns">
<input type="submit" value="로그인" class="btn-primary" />
</div>
</FormRow>
</form>
<div v-else>
이미 로그인 되었습니다. <route-link class="btn-link" to="/">홈</route-link> 으로 이동
</div>
</div>
</div>
</section>
</template>
<script lang="ts">
import { defineComponent, ref, getCurrentInstance, onMounted } from 'vue'
import { IArticle } from '../types/'
import { MainApi } from '../apis/'
import { useRoute } from 'vue-router'
import { Router } from 'vue-router'
export default defineComponent({
name: 'MemberLoginPage',
props: {
globalShare: {
type: Object,
required: true
},
},
setup(props) {
const route = useRoute();
const router:Router = getCurrentInstance()?.appContext.config.globalProperties.$router;
const mainApi:MainApi = getCurrentInstance()?.appContext.config.globalProperties.$mainApi;
const loginIdElRef = ref<HTMLInputElement>();
const loginPwElRef = ref<HTMLInputElement>();
onMounted(() => {
// 만약, route로 들어온 쿼리의 loginId가 null이 아니면
if ( route.query.loginId != null ) {
if ( loginIdElRef.value == null ) {
return;
}
if ( loginPwElRef.value == null ) {
return;
}
// loginIdElRef 값에 route.query.loginId 정보 담기
loginIdElRef.value.value = route.query.loginId as any;
// loginPwElRef에 포커스
loginPwElRef.value.focus();
}
})
function checkAndLogin() {
if ( loginIdElRef.value == null ) {
return;
}
const loginIdEl = loginIdElRef.value;
loginIdEl.value = loginIdEl.value.trim();
if ( loginIdEl.value.length == 0 ) {
alert('아이디를 입력해주세요.');
loginIdEl.focus();
return;
}
if ( loginPwElRef.value == null ) {
return;
}
const loginPwEl = loginPwElRef.value;
loginPwEl.value = loginPwEl.value.trim();
if ( loginPwEl.value.length == 0 ) {
alert('비밀번호를 입력해주세요.');
loginPwEl.focus();
return;
}
//로그인
login(loginIdEl.value, loginPwEl.value);
}
function login(loginId:string, loginPw:string) {
mainApi.member_authKey(loginId, loginPw)
.then(axiosResponse => {
alert(axiosResponse.data.msg);
// 로그인이 fail 상태이면 리턴
if ( axiosResponse.data.fail ) {
return;
}
const authKey = axiosResponse.data.body.authKey;
const loginedMemberId = axiosResponse.data.body.id;
const loginedMemberName = axiosResponse.data.body.name;
const loginedMemberNickname = axiosResponse.data.body.nickname;
localStorage.setItem("authKey", authKey);
localStorage.setItem("loginedMemberId", loginedMemberId + "");
localStorage.setItem("loginedMemberName", loginedMemberName);
localStorage.setItem("loginedMemberNickname", loginedMemberNickname);
props.globalShare.loginedMember = {
authKey,
id:loginedMemberId,
name:loginedMemberName,
nickname:loginedMemberNickname,
};
//alert(axiosResponse.data.msg);
router.replace('/')
});
}
return {
checkAndLogin,
loginIdElRef,
loginPwElRef
}
}
})
</script>
<style scoped>
</style>
<MemberJoinPage.vue>
<template>
<TitleBar>회원가입</TitleBar>
<section class="section section-member-join-form px-2">
<div class="container mx-auto">
<div class="px-6 py-6 bg-white rounded-lg shadow-md">
<form v-if="globalShare.isLogined == false" v-on:submit.prevent="checkAndJoin">
<FormRow title="아이디">
<input ref="loginIdElRef" class="form-row-input" type="text" placeholder="아이디를 입력해주세요.">
</FormRow>
<FormRow title="비밀번호">
<input ref="loginPwElRef" class="form-row-input" type="password" placeholder="비밀번호를 입력해주세요.">
</FormRow>
<FormRow title="비밀번호 확인">
<input ref="loginPwConfirmElRef" class="form-row-input" type="password" placeholder="비밀번호 확인을 해주세요.">
</FormRow>
<FormRow title="이름">
<input ref="nameElRef" class="form-row-input" type="text" placeholder="이름을 입력해주세요.">
</FormRow>
<FormRow title="닉네임">
<input ref="nicknameElRef" class="form-row-input" type="text" placeholder="닉네임을 입력해주세요.">
</FormRow>
<FormRow title="전화번호">
<input ref="cellphoneNoElRef" class="form-row-input" type="tel" placeholder="전화번호를 입력해주세요.">
</FormRow>
<FormRow title="이메일">
<input ref="emailElRef" class="form-row-input" type="email" placeholder="이메일을 입력해주세요.">
</FormRow>
<FormRow title="가입">
<div class="btns">
<input type="submit" value="가입" class="btn-primary" />
</div>
</FormRow>
</form>
<div v-else>
이미 로그인 상태입니다. <route-link class="btn-link" to="/">홈</route-link> 으로 이동
</div>
</div>
</div>
</section>
</template>
<script lang="ts">
import { defineComponent, ref, reactive, getCurrentInstance, onMounted } from 'vue'
import { MainApi } from '../apis/'
import { Router } from 'vue-router';
export default defineComponent({
name: 'MemberJoinPage',
props: {
globalShare: {
type: Object,
required: true
},
},
setup(props) {
const router:Router = getCurrentInstance()?.appContext.config.globalProperties.$router;
const mainApi:MainApi = getCurrentInstance()?.appContext.config.globalProperties.$mainApi;
const loginIdElRef = ref<HTMLInputElement>();
const loginPwElRef = ref<HTMLInputElement>();
const loginPwConfirmElRef = ref<HTMLInputElement>();
const nameElRef = ref<HTMLInputElement>();
const nicknameElRef = ref<HTMLInputElement>();
const cellphoneNoElRef = ref<HTMLInputElement>();
const emailElRef = ref<HTMLInputElement>();
function checkAndJoin() {
// 아이디 체크
if ( loginIdElRef.value == null ) {
return;
}
const loginIdEl = loginIdElRef.value;
loginIdEl.value = loginIdEl.value.trim();
if ( loginIdEl.value.length == 0 ) {
alert('아이디를 입력해주세요.');
loginIdEl.focus();
return;
}
// 비번 체크
if ( loginPwElRef.value == null ) {
return;
}
const loginPwEl = loginPwElRef.value;
loginPwEl.value = loginPwEl.value.trim();
if ( loginPwEl.value.length == 0 ) {
alert('비밀번호를 입력해주세요.');
loginPwEl.focus();
return;
}
// 비번확인 체크
if ( loginPwConfirmElRef.value == null ) {
return;
}
const loginPwConfirmEl = loginPwConfirmElRef.value;
if ( loginPwEl.value != loginPwConfirmEl.value ) {
alert('로그인 비번이 일치하지 않습니다.');
loginPwConfirmEl.focus();
return;
}
// 이름 체크
if ( nameElRef.value == null ) {
return;
}
const nameEl = nameElRef.value;
nameEl.value = nameEl.value.trim();
if ( nameEl.value.length == 0 ) {
alert('이름을 입력해주세요.');
nameEl.focus();
return;
}
// 닉네임 체크
if ( nicknameElRef.value == null ) {
return;
}
const nicknameEl = nicknameElRef.value;
nicknameEl.value = nicknameEl.value.trim();
if ( nicknameEl.value.length == 0 ) {
alert('닉네임을 입력해주세요.');
nicknameEl.focus();
return;
}
// 전화번호 체크
if ( cellphoneNoElRef.value == null ) {
return;
}
const cellphoneNoEl = cellphoneNoElRef.value;
cellphoneNoEl.value = cellphoneNoEl.value.trim();
if ( cellphoneNoEl.value.length == 0 ) {
alert('전화번호를 입력해주세요.');
cellphoneNoEl.focus();
return;
}
// 이메일 체크
if ( emailElRef.value == null ) {
return;
}
const emailEl = emailElRef.value;
emailEl.value = emailEl.value.trim();
if ( emailEl.value.length == 0 ) {
alert('이메일을 입력해주세요.');
emailEl.focus();
return;
}
//회원가입
join(loginIdEl.value, loginPwEl.value, nameEl.value, nicknameEl.value, cellphoneNoEl.value, emailEl.value);
}
function join(loginId:string, loginPw:string, name:string, nickname:string, cellphoneNo:string, email:string) {
mainApi.member_doJoin(loginId, loginPw, name, nickname, cellphoneNo, email)
.then(axiosResponse => {
alert(axiosResponse.data.msg);
if ( axiosResponse.data.fail ) {
return;
}
router.replace('/member/login?loginId=' + loginId)
});
}
return {
checkAndJoin,
loginIdElRef,
loginPwElRef,
loginPwConfirmElRef,
nameElRef,
nicknameElRef,
cellphoneNoElRef,
emailElRef,
}
}
})
</script>
<style scoped>
</style>
'Vue.js > Spring & Vue APP 프로젝트(프론트엔드)' 카테고리의 다른 글
21.03.15 lamplight서비스 프로젝트(리스트 검색기능 구현 진행중..) (0) | 2021.03.15 |
---|---|
21.03.11 lamplight서비스 프로젝트(초기셋팅, 리스트페이지 디자인, 백엔드 게시물불러오기,입력값보내기 테스트까지 완료) (0) | 2021.03.11 |
21.02.24 lamplight서비스 프로젝트(게시물 추가 테스트, 백엔드 연결, 게시물 번호별 리스팅 등) (0) | 2021.02.24 |
21.02.22 lamplight서비스 프로젝트(FormRow 전역 컴포넌트 적용, 상황별 버튼 셋팅, 폰트 적용 등) (0) | 2021.02.22 |
21.02.21 clean서비스 프로젝트(TitleBar 전역 컴포넌트 개념 도입, slot 도입) (0) | 2021.02.21 |