front-end/Vue.js
Axios 기초 배우기 #0 (기본세팅)
정구
2022. 2. 23. 10:12
728x90
Vuetify를 활용하여 템플릿을 꾸미고 서버와의 통신 없이 회원 DB 같은 정보를 만들어 단순한 로그인 기능을 구현하였다.
간단한 라우팅을 지원한다.
앞으로 이 예제를 서버 통신을 통한 로그인 기능으로 개선한다.
src/App.vue
<template>
<div id="app">
<v-app id="inspire">
<v-app id="inspire">
<v-navigation-drawer v-model="drawer" app>
<v-list dense>
<v-list-item :to="{ path: '/' }">
<v-list-item-action>
<v-icon>mdi-home</v-icon>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>Home</v-list-item-title>
</v-list-item-content>
</v-list-item>
<v-list-item v-if="isLogin === false" :to="{ path: '/login' }">
<v-list-item-action>
<v-icon>mdi-email</v-icon>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>로그인</v-list-item-title>
</v-list-item-content>
</v-list-item>
<v-list-item v-else :to="{ path: '/mypage' }">
<v-list-item-action>
<v-icon>mdi-dog</v-icon>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>mypage</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
</v-navigation-drawer>
<v-app-bar app color="indigo" dark>
<v-app-bar-nav-icon
@click.stop="drawer = !drawer"
></v-app-bar-nav-icon>
<v-toolbar-title>Application</v-toolbar-title>
<v-spacer></v-spacer>
<v-toolbar-items class="hidden-sm-and-down">
<v-menu offset-y v-if="isLogin">
<template v-slot:activator="{ on, attrs }">
<v-btn text icon v-bind="attrs" v-on="on">
<v-icon>mdi-dots-vertical</v-icon>
</v-btn>
</template>
<v-list>
<v-list-item :to="{ path: '/mypage' }">
<v-list-item-title>마이페이지</v-list-item-title>
</v-list-item>
<v-list-item @click="$store.dispatch('logout')">
<v-list-item-title>로그아웃</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
<v-btn text v-else :to="{ path: '/login' }">로그인</v-btn>
</v-toolbar-items>
</v-app-bar>
<v-main>
<router-view />
</v-main>
<v-footer color="indigo" app>
<span class="white--text">© {{ new Date().getFullYear() }}</span>
</v-footer>
</v-app>
</v-app>
</div>
</template>
<script>
import { mapState } from "vuex";
export default {
name: "App",
data: () => ({
drawer: null,
}),
computed: {
...mapState(["isLogin"]),
},
methods: {
// ...mapActions(["logout"]),
},
props: {
source: String,
},
};
</script>
src/main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import vuetify from './plugins/vuetify'
Vue.config.productionTip = false
new Vue({
router,
store,
vuetify,
render: h => h(App)
}).$mount('#app')
src/views/Home.vue
<template>
<hello-world />
</template>
<script>
import HelloWorld from '../components/HelloWorld' //HelloWorld 컴포넌트 없어도 됨
export default {
name: 'Home',
components: {
HelloWorld,
},
}
</script>
src/views/Login.vue
<template>
<v-container fill-height style="max-width:450px;">
<v-layout align-center row wrap>
<v-flex xs12>
<v-alert type="error" :value="isLoginError">
아이디와 비밀번호를 확인하세요
</v-alert>
<v-alert type="success" :value="isLogin">
로그인 성공
</v-alert>
<v-card>
<v-toolbar flat color="blue-grey lighten-5">
<v-toolbar-title>로그인</v-toolbar-title>
</v-toolbar>
<div class="pa-3">
<v-text-field v-model="email" label="이메일을 입력하세요">
</v-text-field>
<v-text-field
v-model="password"
type="password"
label="패스워드를 입력하세요"
>
</v-text-field>
<v-btn
block
large
depressed
color="primary"
@click="login({ email, password })"
>로그인</v-btn
>
</div>
</v-card>
</v-flex>
</v-layout>
</v-container>
</template>
\
<script>
import { mapState, mapActions } from "vuex";
export default {
data() {
return {
email: null,
password: null,
};
},
computed: {
...mapState(["isLogin", "isLoginError"]),
},
methods: {
...mapActions(["login"]),
},
};
</script>
src/views/Mypage.vue
<template>
<div>
<h1>{{ userInfo.name }}님 환영합니다.</h1>
</div>
</template>
<script>
import { mapState } from "vuex";
export default {
computed: {
...mapState(["userInfo"]),
},
};
</script>
src/store/index.js
import Vue from "vue";
import Vuex from "vuex";
import router from "../router";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
userInfo: null,
allUsers: [
{ id: 1, name: "hoza", email: "hoza@gmail.com", password: "123456" },
{ id: 2, name: "lego", email: "lego@gmail.com", password: "123456" },
],
isLogin: false,
isLoginError: false,
},
mutations: {
// 로그인이 성공했을 때,
loginSuccess(state, payload) {
state.isLogin = true;
state.isLoginError = false;
state.userInfo = payload;
},
// 로그인이 실패했을 때
loginError(state) {
state.isLogin = false;
state.isLoginError = true;
},
logout(state) {
state.isLogin = false;
state.isLoginError = false;
state.userInfo = null;
},
},
actions: {
//로그인 시도
login({ state, commit }, loginObj) {
let selectedUser = null;
state.allUsers.forEach((user) => {
if (user.email === loginObj.email) selectedUser = user;
});
if (selectedUser === null || selectedUser.password !== loginObj.password)
commit("loginError");
else {
commit("loginSuccess", selectedUser);
router.push({ path: "/mypage" });
}
},
logout({ commit }) {
commit("logout");
router.push({ path: "/" });
},
},
modules: {},
});
src/router/index.js
import Vue from "vue";
import VueRouter from "vue-router";
import store from "../store";
Vue.use(VueRouter);
const rejectAuthUser = (to, from, next) => {
if (store.state.isLogin === true) {
//이미 로그인된 유저니깐 막아야됨
alert("이미 로그인되어있습니다.");
next("/");
} else {
next();
}
};
const onlyAuthUser = (to, from, next) => {
if (store.state.isLogin === false) {
//아직 로그인된 유저니깐 막아야됨
alert("로그인이 필요합니다.");
next("/");
} else {
next();
}
};
const routes = [
{
path: "/",
name: "home",
component: () => import(/* webpackChunkName: "home" */ "../views/Home.vue"),
},
{
path: "/login",
name: "login",
beforeEnter: rejectAuthUser,
component: () =>
import(/* webpackChunkName: "login" */ "../views/Login.vue"),
},
{
path: "/mypage",
name: "mypage",
beforeEnter: onlyAuthUser,
component: () =>
import(/* webpackChunkName: "mypage" */ "../views/Mypage.vue"),
},
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes,
});
export default router;
혹시 몰라 package.json도 남긴다.
src/package.json
{
"name": "login_ex",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^3.6.5",
"vue": "^2.6.11",
"vue-router": "^3.2.0",
"vuetify": "^2.4.0",
"vuex": "^3.4.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-plugin-vuex": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^6.2.2",
"sass": "~1.32.0",
"sass-loader": "^10.0.0",
"vue-cli-plugin-vuetify": "~2.4.2",
"vue-template-compiler": "^2.6.11",
"vuetify-loader": "^1.7.0"
}
}
728x90