Vue简易登录功能思路梳理

328 阅读3分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路

登录注册页面

src\views\login\index.vue

  1.设置redirect立即监听路由重定向数据
  
  2.注册登录点击事件handleLogin
  
      (1)内部调用Vuex的login事件
      
      (2)是否有重定向,有则跳转回登录前页面无则跳转主页面      
      <el-button @click.native.prevent="handleLogin">登录</el-button>
      
      ...
   watch: {
    $route: {
      handler: function(route) {
        this.redirect = route.query && route.query.redirect
      },
      immediate: true
    }
  },
    methods: {
    handleLogin() { 
      this.$refs.loginForm.validate(async (valid) => {
        if (valid) {
      await this.$store.dispatch('user/login',this.loginForm).then((res)=>{
                 this.$router.push({ path: this.redirect || '/' })
      } )
      // this.$router.push('/')
     
        } else {
          console.log('error submit!!')
          return false
        }
      })
    }
  }

主页面

src\layout\components\Navbar.vue

  1.注册登出事件logout
  
    (1)调用Vuex的logout事件
    
    (2)跳转至登录页面并记录登出前页面
 <el-dropdown-item divided @click.native="logout">
            <span style="display:block;">Log Out</span>
 </el-dropdown-item>
 
     ...
     
   methods: {    
   async logout() {
      await this.$store.dispatch('user/logout')
      this.$router.push(`/login?redirect=${this.$route.fullPath}`)
      }
    }

路由配置

src\router\index.js

1.设置登录页面路由

2.设置主页页面路由

  (1)设置子页面路由
  
  (2)设置默认路由

3.设置重置事件
import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

/* Layout */
import Layout from '@/layout'

export const constantRoutes = [
  {
    path: '/login',
    component: () => import('@/views/login/index'),
    hidden: true
  },
  {
    path: '/',
    component: Layout,
    redirect: '/dashboard',
    children: [{
      path: 'dashboard',
      name: 'Dashboard',
      component: () => import('@/views/dashboard/index'),
      meta: { title: 'Dashboard', icon: 'dashboard' }
    }]
  },
]
const createRouter = () => new Router({
  // mode: 'history', // require service support
  scrollBehavior: () => ({ y: 0 }),
  routes: constantRoutes
})

const router = createRouter()

export function resetRouter() {
  const newRouter = createRouter()
  router.matcher = newRouter.matcher // reset router
}

export default router

接口配置

src\api\user.js

 1.设置登录接口
 
 2.根据toekn获取用户信息接口
 
 3.获取用户基本信息接口
import request from "@/utils/request";
/**
 * @description: 登录
 */
export function loginApi(data) {
  return request({
    url: "/api/sys/login",
    method: "post",
    data,
  });
}
 //获取用户信息
export function getInfo(token) {
  return request({
    url: "/api/sys/profile",
    method: "post"
  });
}

/**
 * @description: 获取用户头像
 * @param {*} id 用户id
 * @return {*}
 */
 export function getUserDetailById(id) {
  return request({
    url: `/api/sys/user/${id}`
  })
}

token工具

src\utils\auth.js

import Cookies from 'js-cookie'

const TokenKey = 'vue_admin_template_token'

export function getToken() {
  return Cookies.get(TokenKey)
}

export function setToken(token) {
  return Cookies.set(TokenKey, token)
}

export function removeToken() {
  return Cookies.remove(TokenKey)
}

Vuex

src\store\modules\user.js

   1.获取方法
   
   2.设置state调用getDefaultState方法,设置Object.assign浅拷贝getDefaultState()返回值的信息
   
   3.设置mutations对象存放用于存储state信息的方法
   
   4.设置actions用于异步登录login,调用api中登录接口获取token并存储到state,注意这里的return new Promise()以及使用resolve()接收可以使用await替代
   
   5.设置actions用于获取用户信息getInfo,调用获取用户信息,并将信息存储到state
   
   6.设置actions用于登出logout,调用移除token,重置路由,调用Object.assign浅拷贝getDefaultState()返回值的信息
   
   7.设置actions用于重置token的resetToken事件,重置token,调用Object.assign浅拷贝getDefaultState()返回值的信息 
import { loginApi, getInfo,getUserDetailById } from "@/api/user";
import { getToken, setToken, removeToken } from "@/utils/auth";
import { resetRouter } from "@/router";

const getDefaultState = () => {
  return {
    token: getToken(),
    name: "",
    avatar: "",
    userInfo: {},
  };
};

const state = getDefaultState();

const mutations = {
  RESET_STATE: (state) => {
    Object.assign(state, getDefaultState());
  },
  SET_TOKEN: (state, token) => {
    state.token = token;
  },
  SET_NAME: (state, name) => {
    state.name = name;
    // console.log(state.name,'name');
  },
  SET_AVATAR: (state, avatar) => {
    state.avatar = avatar;
  },
  SET_USERINFO: (state, userInfo) => {
    state.userInfo = userInfo;
  },
};

const actions = {

  login({ commit }, userInfo) {
    return new Promise((resolve, reject) => {
      loginApi(userInfo)
        .then((response) => {
          // console.log(response, 88888);
          // getInfo();
          const { data } = response;
          // console.log(data,'data');
          //将token存储到vuex的state中
          commit("SET_TOKEN", data);
          //  token持久化====cookie来存储的
          setToken(data);
          resolve();
        })
        .catch((error) => {
          reject(error);
        });
    });
  },

  // get user info
  getInfo({ commit, state }) {
    return new Promise(async(resolve, reject) => {
        // getInfo((response)=>{
          const response = await getInfo()
          // console.log(response,'response');
          commit("SET_USERINFO", response.data);
          commit("SET_NAME",response.data.username);
          // console.log(response.data.username,'name');
        // })
    });
  },

  // user logout
  logout({ commit, state }) {
    return new Promise((resolve, reject) => {
          removeToken(); // must remove  token  first
          resetRouter();
          commit("RESET_STATE");
          resolve();
    });
  },

  // remove token
  resetToken({ commit }) {
    return new Promise((resolve) => {
      removeToken(); // must remove  token  first
      commit("RESET_STATE");
      resolve();
    });
  },
};

export default {
  namespaced: true,
  state,
  mutations,
  actions,
};

src\store\getters.js

 设置getters将相应state的不同文件的变量赋予给state的自定义值,并将getters暴露
const getters = {
  sidebar: state => state.app.sidebar,
  device: state => state.app.device,
  token: state => state.user.token,
  avatar: state => state.user.avatar,
  name: state => state.user.name
}
export default getters

请求拦截器

src\utils\request.js

1.设置请求拦截器

   (1)调用getToken事件获取token并将其添加到网址
import axios from "axios";
import { Message } from "element-ui";
import { getToken } from "@/utils/auth";

// create an axios instance
const service = axios.create({
  timeout: 5000, // request timeout
});

// request interceptor
service.interceptors.request.use(
  (config) => {
    if (getToken()) {
      // 携带请求头token
      config.headers["Authorization"] = "Bearer " + getToken();
    }
    return config;
  },
  (error) => {
    console.log(error); // for debug
    return Promise.reject(error);
  }
);

// response interceptor  响应拦截器
service.interceptors.response.use(
 
);

export default service;

路由导航守卫

src\permission.js

   1.下载进度条包引入并设置
   
   2.设置白名单
   
   3.设置路由前置守卫(到哪去,从哪来,放行)
   
       (1)开启进度条
       
       (2)设置字体
       
       (3)获取token
       
       (4)根据token判断是否登录    
       
           /1 有token
           
              //1 去的登录页面
           
                  ///1 放行,关闭进度条
                  
               //2 去的不是首页
               
                  ///1 已经获取到用户信息
                  
                       ////1 放行,关闭进度条
                  
                  ///2 未获取用户信息
                  
                       ////1 获取用户信息
                       
                       ////2 放行,关闭进度条
       
            /2 没有token
            
               //1 在白名单中
               
                   ///1 放行,关闭进度条
               
               //2 没在白名单中
               
                   ///1 记录放行前页面
                   
                   ///2 放行并关闭进度条
import router from "./router";
import store from "./store";
import { Message } from "element-ui";
import NProgress from "nprogress"; // progress bar
import "nprogress/nprogress.css"; // progress bar style
import { getToken } from "@/utils/auth"; // get token from cookie
import getPageTitle from "@/utils/get-page-title";

NProgress.configure({ showSpinner: false }); // NProgress Configuration

const whiteList = ["/login"]; // no redirect whitelist

/* 路由导航守卫=====只要有路由值发生改变就会触发
beforeEach====跳转之前
afterEach=====跳转之后
*/
router.beforeEach(async (to, from, next) => {
  NProgress.start();
  document.title = getPageTitle(to.meta.title);
  const hasToken = getToken();
  // next();
  // console.log(hasToken,'tt');
  if (hasToken) {
    //next();
    if (to.path === "/login") {
      next("/");
      NProgress.done();
    } else {
      const hasGetUserInfo = store.getters.name; // 获取的用户信息
      // console.log(hasGetUserInfo, 988);
      if (hasGetUserInfo) {
        next();
      } else {
        store.dispatch("user/getInfo");
        next();
      }
      NProgress.done();
    }
  } else {
  //   // 表示没有登录
    if (whiteList.includes(to.path)) {
      next();
      NProgress.done();
    } else {
 the login page.
      next(`/login?redirect=${this.$route.fullPath}`);
      NProgress.done();
    }
  }
});

router.afterEach(() => {

});

设置

vue.config.js

 配置代理服务器解决跨域问题
module.exports = {
  ...
  devServer: {
   ...
    proxy:{
      /* 代理服务器
      + 代理服务器:http://localhost:9999/
      + 目标服务器:http://ihrm-java.itheima.net
      /api===只要请求地址中有api的就会进入代理服务器
      '/api':{
        target:'http://ihrm-java.itheima.net'
      }
    }
  },