1
This commit is contained in:
412
demo-project/_doc/登录跳转首页修复说明.md
Normal file
412
demo-project/_doc/登录跳转首页修复说明.md
Normal file
@@ -0,0 +1,412 @@
|
||||
# 登录跳转首页修复说明
|
||||
|
||||
## 🎯 需求
|
||||
|
||||
1. 登录成功后自动跳转到首页
|
||||
2. 访问 `/` 时自动重定向到 `/home`
|
||||
|
||||
## 📋 问题分析
|
||||
|
||||
### 原来的问题
|
||||
|
||||
**登录流程**:
|
||||
```
|
||||
用户登录
|
||||
↓
|
||||
调用 handleLogin
|
||||
↓
|
||||
保存 token 和 authorityMenus
|
||||
↓
|
||||
显示"登录成功!"
|
||||
↓
|
||||
window.location.reload() ← ❌ 刷新当前页面(/login)
|
||||
↓
|
||||
停留在登录页面 ❌
|
||||
```
|
||||
|
||||
**问题**:
|
||||
- 登录成功后刷新了登录页面
|
||||
- 虽然路由守卫会检测到 token 并重定向到首页
|
||||
- 但是刷新操作会导致页面停留在 `/login`
|
||||
|
||||
### 路由守卫逻辑
|
||||
|
||||
`src/router/index.js` 中的路由守卫:
|
||||
```javascript
|
||||
router.beforeEach((to, from, next) => {
|
||||
const token = getToken()
|
||||
|
||||
if (!token && to.name !== 'login') {
|
||||
// 未登录且访问非登录页 → 跳转到登录页
|
||||
next({ name: 'login' })
|
||||
} else if (!token && to.name === 'login') {
|
||||
// 未登录且访问登录页 → 允许访问
|
||||
next()
|
||||
} else if (token && to.name === 'login') {
|
||||
// 已登录且访问登录页 → 重定向到首页
|
||||
next({ name: homeName }) // homeName = 'home'
|
||||
} else {
|
||||
// 其他情况 → 允许访问
|
||||
next()
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- 如果已登录(有 token)且访问登录页,会重定向到首页
|
||||
- 但是 `window.location.reload()` 会刷新当前页面,不会触发路由跳转
|
||||
|
||||
### 主路由重定向配置
|
||||
|
||||
`src/utils/uiTool.js` 中的主路由配置:
|
||||
```javascript
|
||||
let mainRoute = {
|
||||
path: '/',
|
||||
name: '主视图',
|
||||
redirect: '/home', // ← 访问 / 时重定向到 /home
|
||||
component: Main,
|
||||
children: []
|
||||
}
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- 访问 `/` 时会自动重定向到 `/home`
|
||||
- 前提是 `/home` 路由存在(从后端权限菜单生成)
|
||||
|
||||
## ✅ 解决方案
|
||||
|
||||
### 修改登录成功后的跳转逻辑
|
||||
|
||||
**修改文件**:`src/views/login/login.vue`
|
||||
|
||||
**修改前**:
|
||||
```javascript
|
||||
async handleSubmit({ userName, password }) {
|
||||
try {
|
||||
let userFrom = { name: userName, password: password }
|
||||
await this.handleLogin({
|
||||
userFrom,
|
||||
Main,
|
||||
ParentView,
|
||||
Page404
|
||||
})
|
||||
this.$Message.success('登录成功!')
|
||||
window.location.reload() // ❌ 刷新当前页面(/login)
|
||||
} catch (error) {
|
||||
// 错误处理
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**修改后**:
|
||||
```javascript
|
||||
async handleSubmit({ userName, password }) {
|
||||
try {
|
||||
let userFrom = { name: userName, password: password }
|
||||
await this.handleLogin({
|
||||
userFrom,
|
||||
Main,
|
||||
ParentView,
|
||||
Page404
|
||||
})
|
||||
this.$Message.success('登录成功!')
|
||||
|
||||
// ✅ 跳转到首页(使用 location.href 触发完整页面加载)
|
||||
setTimeout(() => {
|
||||
window.location.href = window.location.origin + window.location.pathname + '#/'
|
||||
}, 500)
|
||||
} catch (error) {
|
||||
// 错误处理
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**改进点**:
|
||||
- ✅ 使用 `window.location.href` 跳转到 `#/`
|
||||
- ✅ 触发完整的页面加载
|
||||
- ✅ 路由会重定向到 `/home`
|
||||
- ✅ 延迟 500ms 确保提示信息显示
|
||||
|
||||
## 📊 新的登录流程
|
||||
|
||||
### 完整流程
|
||||
|
||||
```
|
||||
用户输入用户名密码
|
||||
↓
|
||||
点击登录
|
||||
↓
|
||||
调用 handleLogin action
|
||||
↓
|
||||
调用登录接口
|
||||
↓
|
||||
保存 token 到 localStorage
|
||||
↓
|
||||
保存用户信息到 Vuex
|
||||
↓
|
||||
调用 setAuthorityMenus
|
||||
├─ 尝试获取权限菜单
|
||||
├─ 如果失败,使用默认菜单
|
||||
└─ 保存到 localStorage.authorityMenus
|
||||
↓
|
||||
显示"登录成功!"提示
|
||||
↓
|
||||
延迟 500ms
|
||||
↓
|
||||
跳转到 #/ (window.location.href)
|
||||
↓
|
||||
触发完整页面加载
|
||||
↓
|
||||
框架初始化
|
||||
↓
|
||||
从 localStorage 读取 authorityMenus
|
||||
↓
|
||||
生成路由(包括首页)
|
||||
↓
|
||||
访问 / 路由
|
||||
↓
|
||||
重定向到 /home ✅
|
||||
↓
|
||||
显示首页 ✅
|
||||
```
|
||||
|
||||
### 路由重定向流程
|
||||
|
||||
```
|
||||
访问 #/
|
||||
↓
|
||||
匹配主路由 { path: '/', redirect: '/home' }
|
||||
↓
|
||||
重定向到 /home
|
||||
↓
|
||||
匹配首页路由 { path: '/home', component: HomePage }
|
||||
↓
|
||||
显示首页组件 ✅
|
||||
```
|
||||
|
||||
### 已登录用户访问登录页
|
||||
|
||||
```
|
||||
已登录用户访问 #/login
|
||||
↓
|
||||
路由守卫检测到 token
|
||||
↓
|
||||
检测到访问登录页
|
||||
↓
|
||||
重定向到首页 next({ name: 'home' })
|
||||
↓
|
||||
显示首页 ✅
|
||||
```
|
||||
|
||||
## 🎯 关键点说明
|
||||
|
||||
### 1. 为什么使用 `window.location.href` 而不是 `this.$router.push`?
|
||||
|
||||
**`this.$router.push({ path: '/' })`**:
|
||||
- 只是客户端路由跳转
|
||||
- 不会重新加载页面
|
||||
- 不会重新初始化框架
|
||||
- 不会重新从 localStorage 读取 authorityMenus
|
||||
|
||||
**`window.location.href = '#/'`**:
|
||||
- 触发完整的页面加载
|
||||
- 重新初始化框架
|
||||
- 重新从 localStorage 读取 authorityMenus
|
||||
- 重新生成路由
|
||||
- 确保路由和菜单正确加载
|
||||
|
||||
### 2. 为什么延迟 500ms?
|
||||
|
||||
```javascript
|
||||
setTimeout(() => {
|
||||
window.location.href = window.location.origin + window.location.pathname + '#/'
|
||||
}, 500)
|
||||
```
|
||||
|
||||
**原因**:
|
||||
- 让"登录成功!"提示信息有时间显示
|
||||
- 给用户更好的体验
|
||||
- 确保 localStorage 写入完成
|
||||
|
||||
### 3. URL 构造说明
|
||||
|
||||
```javascript
|
||||
window.location.origin + window.location.pathname + '#/'
|
||||
```
|
||||
|
||||
**示例**:
|
||||
- `window.location.origin` = `http://localhost:8080`
|
||||
- `window.location.pathname` = `/` 或 `/demo-project/`
|
||||
- 最终 URL = `http://localhost:8080/#/` 或 `http://localhost:8080/demo-project/#/`
|
||||
|
||||
**为什么这样构造**:
|
||||
- 兼容不同的部署路径
|
||||
- 确保 hash 路由正确
|
||||
- 避免硬编码 URL
|
||||
|
||||
### 4. 主路由的 redirect 配置
|
||||
|
||||
```javascript
|
||||
let mainRoute = {
|
||||
path: '/',
|
||||
redirect: '/home',
|
||||
component: Main,
|
||||
children: [
|
||||
{ path: '/home', name: 'home', component: HomePage },
|
||||
// ... 其他路由
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**工作原理**:
|
||||
- 访问 `/` 时,自动重定向到 `/home`
|
||||
- `/home` 路由由后端权限菜单生成
|
||||
- 如果后端没有返回首页配置,会使用默认菜单配置
|
||||
|
||||
## ✅ 验证清单
|
||||
|
||||
### 登录流程验证
|
||||
|
||||
- ✅ 访问登录页面
|
||||
- ✅ 输入用户名密码
|
||||
- ✅ 点击登录
|
||||
- ✅ 显示"登录成功!"提示
|
||||
- ✅ 自动跳转到首页
|
||||
- ✅ 首页正确显示
|
||||
- ✅ 菜单正确显示
|
||||
|
||||
### 路由重定向验证
|
||||
|
||||
- ✅ 登录后访问 `#/` 自动重定向到 `#/home`
|
||||
- ✅ 已登录状态访问 `#/login` 自动重定向到 `#/home`
|
||||
- ✅ 未登录状态访问 `#/home` 自动重定向到 `#/login`
|
||||
|
||||
### 刷新页面验证
|
||||
|
||||
- ✅ 登录后刷新页面,停留在当前页面
|
||||
- ✅ 菜单和路由保持正确
|
||||
- ✅ 用户信息保持正确
|
||||
|
||||
## 🔧 相关配置
|
||||
|
||||
### 路由守卫配置
|
||||
|
||||
**文件**:`src/router/index.js`
|
||||
|
||||
```javascript
|
||||
export const setupRouterGuards = (router, ViewUI, homeName = 'home') => {
|
||||
router.beforeEach((to, from, next) => {
|
||||
const token = getToken()
|
||||
ViewUI.LoadingBar.start()
|
||||
|
||||
if (!token && to.name !== 'login') {
|
||||
// 未登录 → 跳转到登录页
|
||||
next({ name: 'login' })
|
||||
} else if (!token && to.name === 'login') {
|
||||
// 未登录访问登录页 → 允许
|
||||
next()
|
||||
} else if (token && to.name === 'login') {
|
||||
// 已登录访问登录页 → 重定向到首页
|
||||
next({ name: homeName })
|
||||
} else {
|
||||
// 其他情况 → 允许
|
||||
next()
|
||||
}
|
||||
})
|
||||
|
||||
router.afterEach(to => {
|
||||
ViewUI.LoadingBar.finish()
|
||||
window.scrollTo(0, 0)
|
||||
})
|
||||
|
||||
return router
|
||||
}
|
||||
```
|
||||
|
||||
### 主路由配置
|
||||
|
||||
**文件**:`src/utils/uiTool.js`
|
||||
|
||||
```javascript
|
||||
static getRoutes(Main, ParentView, Page404) {
|
||||
let mainRoute = {
|
||||
path: '/',
|
||||
name: '主视图',
|
||||
redirect: '/home',
|
||||
component: Main,
|
||||
meta: { title: '首页', notCache: true },
|
||||
children: []
|
||||
}
|
||||
|
||||
// 从 localStorage 读取权限菜单
|
||||
if (localStorage.authorityMenus && localStorage.authorityMenus !== 'undefined') {
|
||||
let authorityMenus = JSON.parse(localStorage.authorityMenus) || []
|
||||
|
||||
if (authorityMenus && authorityMenus.length > 0) {
|
||||
let menus = uiTool.transformTree(authorityMenus)
|
||||
let curRoutes = uiTool.menuToRoute(menus, ParentView, Page404)
|
||||
|
||||
// 使用后端返回的路由(包括首页)
|
||||
mainRoute.children = curRoutes
|
||||
}
|
||||
}
|
||||
|
||||
return mainRoute
|
||||
}
|
||||
```
|
||||
|
||||
## 💡 最佳实践
|
||||
|
||||
### 1. 登录后的跳转
|
||||
|
||||
**推荐**:
|
||||
```javascript
|
||||
// 使用 location.href 触发完整页面加载
|
||||
window.location.href = window.location.origin + window.location.pathname + '#/'
|
||||
```
|
||||
|
||||
**不推荐**:
|
||||
```javascript
|
||||
// 只刷新当前页面,不跳转
|
||||
window.location.reload()
|
||||
|
||||
// 客户端路由跳转,不重新加载
|
||||
this.$router.push({ path: '/' })
|
||||
```
|
||||
|
||||
### 2. 路由守卫
|
||||
|
||||
**推荐**:
|
||||
- 在路由守卫中统一处理登录状态检查
|
||||
- 已登录访问登录页时自动重定向到首页
|
||||
- 未登录访问受保护页面时自动重定向到登录页
|
||||
|
||||
### 3. 主路由配置
|
||||
|
||||
**推荐**:
|
||||
- 设置 `redirect: '/home'` 确保访问 `/` 时重定向到首页
|
||||
- 从后端权限菜单生成路由
|
||||
- 提供默认菜单配置作为降级方案
|
||||
|
||||
## 📝 总结
|
||||
|
||||
### 修改内容
|
||||
|
||||
- ✅ 修改了登录成功后的跳转逻辑
|
||||
- ✅ 使用 `window.location.href` 跳转到首页
|
||||
- ✅ 触发完整页面加载
|
||||
- ✅ 确保路由和菜单正确初始化
|
||||
|
||||
### 效果
|
||||
|
||||
- ✅ 登录成功后自动跳转到首页
|
||||
- ✅ 访问 `/` 自动重定向到 `/home`
|
||||
- ✅ 已登录访问登录页自动重定向到首页
|
||||
- ✅ 用户体验更流畅
|
||||
|
||||
---
|
||||
|
||||
**登录跳转首页功能已完成!** 🎉
|
||||
|
||||
现在登录成功后会自动跳转到首页,访问 `/` 也会正确重定向到 `/home`。
|
||||
|
||||
Reference in New Issue
Block a user