带登录权限的单页应用开发实战
本任务将指导您使用 Vue.js、Vue Router 和 Vuex 开发一个带登录权限的单页应用(SPA)。核心目标是实现登录页面、首页、个人中心(需权限访问)和404页面的路由与状态管理。关键点包括:登录流程、权限控制、状态持久化和路由跳转优化。下面我将逐步解释实现过程,确保结构清晰,并提供代码示例。
1. 配置路由规则(区分公开路由和私有路由)
首先,我们需要定义路由规则,区分公开路由(如登录页和404页)和私有路由(如首页和个人中心,需登录才能访问)。使用 Vue Router 的 router/index.js 文件配置路由。
- 公开路由 :登录页(
/login)和404页(/*)。 - 私有路由 :首页(
/)和个人中心(/profile)。 - 逻辑说明 :私有路由需要权限控制,通过路由元信息(
meta)标记哪些路由需要登录。
javascript
// router/index.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import Login from '../views/Login.vue';
import Home from '../views/Home.vue';
import Profile from '../views/Profile.vue';
import NotFound from '../views/NotFound.vue';
Vue.use(VueRouter);
const routes = [
{
path: '/login',
name: 'Login',
component: Login,
meta: { requiresAuth: false } // 公开路由
},
{
path: '/',
name: 'Home',
component: Home,
meta: { requiresAuth: true } // 私有路由,需登录
},
{
path: '/profile',
name: 'Profile',
component: Profile,
meta: { requiresAuth: true } // 私有路由
},
{
path: '*',
component: NotFound,
meta: { requiresAuth: false } // 404页,公开路由
}
];
const router = new VueRouter({
mode: 'history',
routes
});
export default router;
2. Vuex 封装用户模块(处理登录状态)
使用 Vuex 管理用户状态,包括 token 和用户信息。定义 state、mutation 和 action 来处理登录异步请求和状态变更。
- state:存储 token 和用户信息。
- mutation:直接修改状态(如设置 token)。
- action:处理登录逻辑(如调用 API 验证账号密码),并提交 mutation。
- 逻辑说明:登录成功后,将 token 存储到 state,并持久化状态。
javascript
// store/index.js
import Vue from 'vue';
import Vuex from 'vuex';
import createPersistedState from 'vuex-persistedstate'; // 用于状态持久化
Vue.use(Vuex);
export default new Vuex.Store({
state: {
token: null, // 存储登录 token
userInfo: null // 存储用户信息
},
mutations: {
SET_TOKEN(state, token) {
state.token = token;
},
SET_USER_INFO(state, userInfo) {
state.userInfo = userInfo;
},
CLEAR_USER(state) {
state.token = null;
state.userInfo = null;
}
},
actions: {
async login({ commit }, { username, password }) {
// 模拟 API 调用验证账号密码
try {
const response = await fetch('/api/login', {
method: 'POST',
body: JSON.stringify({ username, password })
});
const data = await response.json();
if (data.success) {
commit('SET_TOKEN', data.token);
commit('SET_USER_INFO', data.userInfo);
return true; // 登录成功
}
return false; // 登录失败
} catch (error) {
console.error('登录失败:', error);
return false;
}
},
logout({ commit }) {
commit('CLEAR_USER');
}
},
getters: {
isAuthenticated: state => !!state.token // 检查是否登录
},
plugins: [createPersistedState()] // 状态持久化插件,页面刷新后状态不丢失
});
3. 实现全局路由守卫(权限拦截与目标页面缓存)
使用 Vue Router 的全局前置守卫(beforeEach)检查用户登录状态。如果访问私有路由未登录,则拦截并跳转到登录页,同时缓存目标路径以便登录后回跳。
- 逻辑说明 :在守卫中,检查路由的
meta.requiresAuth和 Vuex 的登录状态。未登录时,跳转至登录页,并通过next函数传递目标路径。 - 优化:登录成功后,跳转回原目标页面。
javascript
// 在 router/index.js 中,添加守卫
router.beforeEach((to, from, next) => {
const requiresAuth = to.matched.some(record => record.meta.requiresAuth);
const isAuthenticated = store.getters.isAuthenticated; // 假设 store 已导入
if (requiresAuth && !isAuthenticated) {
// 未登录访问私有路由,跳转到登录页,并存储目标路径
next({
path: '/login',
query: { redirect: to.fullPath } // 缓存目标路径
});
} else if (to.path === '/login' && isAuthenticated) {
// 已登录时访问登录页,直接跳转首页
next('/');
} else {
next(); // 允许访问
}
});
4. 编写登录组件(表单验证 + 调用 Vuex action)
创建登录组件,实现表单验证和登录逻辑。调用 Vuex action 处理登录,成功后根据缓存的目标路径跳转。
- 表单验证:使用简单验证(如非空检查),实际项目中可用库如 Vuelidate。
- 逻辑说明:登录成功后,检查是否有重定向路径,并跳转。
vue
<!-- views/Login.vue -->
<template>
<div>
<form @submit.prevent="handleLogin">
<input v-model="username" placeholder="用户名" />
<input v-model="password" type="password" placeholder="密码" />
<button type="submit">登录</button>
</form>
<p v-if="error">{{ error }}</p>
</div>
</template>
<script>
import { mapActions } from 'vuex';
export default {
data() {
return {
username: '',
password: '',
error: ''
};
},
methods: {
...mapActions(['login']),
async handleLogin() {
if (!this.username || !this.password) {
this.error = '用户名和密码不能为空';
return;
}
const success = await this.login({
username: this.username,
password: this.password
});
if (success) {
// 登录成功,检查是否有重定向路径
const redirect = this.$route.query.redirect || '/';
this.$router.push(redirect);
} else {
this.error = '登录失败,请检查账号密码';
}
}
}
};
</script>
5. 编写首页和个人中心组件(从 Vuex 获取用户信息)
创建首页和个人中心组件,从 Vuex 获取用户信息并渲染。个人中心需权限访问,已在路由守卫中处理。
- 首页组件:显示欢迎信息。
- 个人中心组件:显示用户详情,需登录才能访问。
vue
<!-- views/Home.vue -->
<template>
<div>
<h1>欢迎来到首页</h1>
<p v-if="userInfo">你好,{{ userInfo.name }}</p>
</div>
</template>
<script>
import { mapState } from 'vuex';
export default {
computed: {
...mapState(['userInfo'])
}
};
</script>
vue
<!-- views/Profile.vue -->
<template>
<div>
<h1>个人中心</h1>
<div v-if="userInfo">
<p>用户名:{{ userInfo.name }}</p>
<p>邮箱:{{ userInfo.email }}</p>
</div>
<button @click="logout">退出登录</button>
</div>
</template>
<script>
import { mapActions, mapState } from 'vuex';
export default {
computed: {
...mapState(['userInfo'])
},
methods: {
...mapActions(['logout']),
logout() {
this.logout();
this.$router.push('/login');
}
}
};
</script>
总结要点回顾
通过本实战,您已掌握带登录权限的 SPA 开发核心流程:
- Vue Router 与 Vuex 联动 :路由守卫(
beforeEach)结合 Vuex 状态(如isAuthenticated)实现权限控制。例如,访问私有路由时,检查状态:如果用户未登录(即 \\text{isAuthenticated} = \\text{false} ),则拦截跳转。 - 权限控制核心逻辑:基于"状态存储 + 路由拦截"的模式。状态存储在 Vuex,路由守卫动态判断权限,确保安全访问。
- 实战解决方案 :
- 状态持久化 :使用插件如
vuex-persistedstate,防止页面刷新后登录状态丢失。 - 路由跳转优化 :在登录页通过
query参数缓存目标路径,登录后自动跳转。 - 其他优化:表单验证、错误处理等提升用户体验。
- 状态持久化 :使用插件如
此方案高效可靠,适用于大多数 SPA 应用。实践中,可扩展更多功能如角色权限或多因素认证。