ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Axios 기초 배우기 #0 (기본세팅)
    front-end/Vue.js 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">&copy; {{ 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

    댓글

Designed by Tistory.