基于vue的登录demo
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()// 当该组件消失的应该取消监听
}