基于vue实现的登录页面(含跳转鉴权操作)

549 阅读3分钟

基于vue的登录demo

image.png

image.png

1.创建组件

首先创建一个MyHome主页面,设置一个nav组件,实现组件路由的切换,分组件包含HomePage,NewsPage,UserPage,LoginPage,LoadingPage等组件

<template>
  <div class="myhome">
      <div class="navtop">
        <router-link to="/homepage">Home</router-link>
        <router-link to="/news">News</router-link>
        <span v-if="status === 'loading'">loading...</span>
        <template v-else-if="status === 'login'">
          <router-link to="/user">{{user.name}}</router-link>
          <span @click="loginout" class="loginout">退出</span>
        </template>
        <router-link to="/login" v-else>login</router-link>
      </div> 
      <router-view></router-view>
  </div>
</template>

2.路由配置

在路由配置中需要注意的是,如果使用的vue那么相应的路由组件应该为vue-router3

//  安装vue-router3.x版本
npm install vue-router@3

下面是路由配置文件

// 引入vue和vue-router插件
import Vue from 'vue'
import VueRouter from 'vue-router'
// 使用vue-router
Vue.use(VueRouter)
const route = [
    {path: '/', component: MyHome ,
        children:[
            {path:'/homepage', component: HomePage},
            {path:'/news', component: NewsPage ,meta :{
                auth:true
            }},
            {path: 'user',component:UserCenter , meta:{
                auth:true
            }},
            { path: '/login',component:LoginPage},
            {path:'/loading',component:LoadingPage}
    ]
}
const router = new VueRouter({
        route
})
// 导出路由配置
export default router

3.登录接口模拟

正常情况下,登陆需要调用登录接口,如果没有可用的登录接口,可以自己手动编写一个模拟接口使用,以下是模拟接口的代码实现。

// 模拟网络请求延时效果
function delay(duration){
   return new Promise((resolve) => {
        setTimeout(()=>{
            resolve()
        },duration)
    })
}
// 模拟登录接口
export async function loginin(loginId,loginPwd){
    await delay(1000)
    if(loginId === "admin" && loginPwd === "123456"){
        const user ={
            loginId,
            name:'管理员'
        }
// 登陆成功后,将得到的user数据保存在localstorage中
        localStorage.setItem("user",JSON.stringify(user))
        return user
    }
  return null
}
// 注销账号,将localstorage中的数据清除
export async function loginout(){
    await delay(1000)
    localStorage.removeItem("user")
}
 // 用来检测用户是否登录,拿localstorage里面的值进行登录
export async function whoAmI(){
    await delay(1000)
    const user = localStorage.getItem("user")
    if(user) {
        return JSON.parse(user)
    }
    return null
}

4.vuex文件配置

// 引入vue以及vuex插件
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Store.Vuex({
    // 引入store模块
   loginuser
})
export default store
export default {
namespaced:true,
    // 开启命名空间后,只有加上模块前缀才能调用模块内的数据
    state:{
        loading:false,
        user: null
    },
    // store模块中的响应式数据,类似于computed
    getters:{
        status(state){
            if(state.loading) {
                return "loading"
            }
            else if(state.user){
                return "login"
            }
            else {
                return 'unlogin'
            }
        }
    },
    mutations:{
        setloading(state,payload) {
            state.loading = payload
        },
        setuser(state,payload) {
            state.user = payload
        }
    },
    actions:{
        async login(ctx,payload){
            ctx.commit('setloading',true)
            const res = await loginApi.loginin(payload.loginId,payload.loginPwd)
            ctx.commit("setuser",res)
            ctx.commit("setloading",false)
        },
        async loginout(ctx){
            ctx.commit("setloading",true)
            await loginApi.loginout()
            ctx.commit("setuser",null)
            ctx.commit("setloading",false)

        },
        // 获取页面缓存
        async WhoAmI(ctx){
            ctx.commit("setloading",true)
            const res = await loginApi.whoAmI()
            ctx.commit("setuser",res)
            ctx.commit("setloading",false)
        }
    }

使用辅助函数mapstate,mapgetters简化组件中的代码书写

//  loginuser为命名空间名
this.$strore.getters["loginuser/status"]
this.$store.state.loginuser.loading/user => 
computed:{
...mapstate("loginuser,['loading','user']"),
...mapgetters("loginuser",['status'])
}

5.获取缓存数据(数据重新加载)

在vue实例创建之前,获取缓存

//   main.js文件
import store from "./store"
store.dispatch("loginuser/WhoAmI")

6.登录鉴权问题

在一些常见的软件中,部分组件需要相应的权限才能跳转到该页面,因此我们在页面跳转之前需要对其进行鉴权,即根据是否登录等来判断是否有权限进入该页面

//  给路由配置配置项设置一个meta属性
 {path:'/news', component: NewsPage ,meta :{
            auth:true
        }},
        {path: 'user',component:UserCenter , meta:{
            auth:true
        }},
//  router/index.js文件里对需要鉴权的路由进行判定
const status = store.getters["loginuser/status"]
router.beforeEach(to,from,next){
    if(to.meta.auth){
    //  如果需要鉴权,判断当前status状态来判定其能否进入页面
        if(status === 'loading') {
        next({
        //  如果状态是loading则跳转至loading页面
        path:"/loading"
        // 路由传参将需要跳转的路由携带过去
        query:{
        url: to.fullPath
        }
        })
        }
        else if(status === 'login') {
        next()
        }
        //  如果未登录则跳转至login页面
        else next("/login")
    }

}

当跳转至login页面时,需要监控当前的status的变化,当status !== loading触发相应的回到函数,加载到对应的页面

this.unWatch = this.$store.watch({
//  第一个函数是监控status的变化,变化时触发回调函数
()=>this.$store.getters["loginuser/status"],
(status)=>{
if(status !== 'loading'){
this.$router.push(this.$route.query.url)
}
},
{immediate:true}// 刷新页面时也会触发
})
destroyed(){
this.unWatch()// 当该组件消失的应该取消监听
}