-
Axios 기초 배우기 #0 (기본세팅)front-end/Vue.js 2022. 2. 23. 10:12728x90
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'front-end > Vue.js' 카테고리의 다른 글
Axios 기초 배우기 #2 (GET 방식으로 통신하기) (0) 2022.02.23 Axios 기초 배우기 #1 (페이크 API서버와 Postman) (0) 2022.02.23 Vuex 기초배우기 #6 (actions) (0) 2022.02.23 Vuex 기초배우기 #5 (mutations) (0) 2022.02.22 Vuex 기초배우기 #4 (mapState, mapGetters) (0) 2022.02.22