这里选择了 vue-element-admin 这个项目骨架,它采用的技术与我们之前学过的较为契合
git clone https://gitee.com/panjiachen/vue-element-admin.git study03_vue2_client_action
cd study03_vue2_client_action
# 列出所有分支
git branch -a
# 我们当前在的master分支是只支持英文的,需要切换分支
# git checkout -b 创建并切换分支
git checkout -b i18n remotes/origin/i18n
# 将git的地址凡是以git://打头的,都替换为https://打头
# 因为npm的过程需要访问以为git仓库,如果是git:// 打头,下载的时候可能会出现问题
git config --global url."https://".insteadOf git://
npm install
npm run dev
此时系统已经运行起来了 ,会有同学有疑问,它没有后端服务器的支撑,是怎么完成整个登录的流程的呢,整个登录的流程是如何走通的呢?
实际上点击登录按钮之后,是会发一个真正的请求,只不过这个请求不是发给后台的,是发给9527自己的,9527里有一段自己的代码来处理请求,只不过他返回了一个mock的响应(假的响应),这个加的响应就包含了登录需要的一些模拟数据。
具体的跟着视频看
开发环境下执行下面命令
npm run dev
根据刚才登录发起的请求,通过后缀user/login
可以找到两个文件:
我们想要让他不把请求发到自己mock的服务端,而是发给我们自己的后端,需要修改这个baseURL,根据刚才请求的前缀可以找到开发环境的baseURL在文件 .env.development
中:
在开发环境下,后端访问路径起始路径配置在文件 .env.development
中
# base api
# VUE_APP_BASE_API = '/dev-api'
VUE_APP_BASE_API = 'http://localhost:8080/api'
http://localhost:9527/dev-api
的 mock-server 获得的都是模拟数据VUE_APP_BASE_API = 'http://localhost:8080/api'
修改baseURL之后需要重启服务器
发送请求的 axios 工具被封装在 src/utils/request.js 中
import axios from 'axios'
import { MessageBox, Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
// create an axios instance
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
// withCredentials: true, // send cookies when cross-domain requests
timeout: 5000 // request timeout
})
// ...
原有代码的 URI 路径都是这样的:
/vue-element-admin/user/login
/vue-element-admin/user/info
/vue-element-admin/user/logout
...
如果觉得不爽,可以来一个全局替换:
/user/login
/user/info
/user/logout
...
token 的请求头修改一下,在 src/utils/request.js 中
...
service.interceptors.request.use(
config => {
// do something before request is sent
if (store.getters.token) {
// let each request carry token
// ['X-Token'] is a custom headers key
// please modify it according to the actual situation
config.headers['Authorization'] = getToken()
}
return config
},
error => {
// do something with request error
console.log(error) // for debug
return Promise.reject(error)
}
)
...
src/views/login/index.vue
<script>
import { validUsername } from '@/utils/validate'
import LangSelect from '@/components/LangSelect'
import SocialSign from './components/SocialSignin'
export default {
// ...
methods: {
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true
this.$store.dispatch('user/login', this.loginForm)
.then(() => {
this.$router.push({ path: this.redirect || '/', query: this.otherQuery })
this.loading = false
})
.catch(() => {
this.loading = false
})
} else {
console.log('error submit!!')
return false
}
})
}
// ...
}
}
</script>
这里调用了 store 的 actions,user/login
src/router/index.js
的路由表可知,会重定向至 /dashboardsrc/store/modules/user.js
import { login, logout, getInfo } from '@/api/user'
// ...
const actions = {
// user login
login({ commit }, userInfo) {
const { username, password } = userInfo
return new Promise((resolve, reject) => {
login({ username: username.trim(), password: password }).then(response => {
const { data } = response
commit('SET_TOKEN', data.token)
setToken(data.token)
resolve()
}).catch(error => {
reject(error)
})
})
}
// ...
}
src/api/user.js
,请求成功使用 commit 将 token 存入 mutations,同时往 cookie 存储了一份src/api/user.js
import request from '@/utils/request'
export function login(data) {
return request({
url: '/user/login',
method: 'post',
data
})
}
// ...
src/utils/request.js
import axios from 'axios'
import { MessageBox, Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
// create an axios instance
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
// withCredentials: true, // send cookies when cross-domain requests
timeout: 5000 // request timeout
})
// ...
service.interceptors.response.use(
// ...
response => {
const res = response.data
if (res.code !== 20000) {
// ...
} else {
return res
}
},
error => {
// ...
}
)
export default service
src/permission.js
登录成功后,只是获得了 token,还未获取用户信息,获取用户信息是在路由跳转的 beforeEach 里做的
关键代码
import router from './router'
// ...
router.beforeEach(async(to, from, next) => {
// ...
const hasToken = getToken()
if (hasToken) {
if (to.path === '/login') {
// ...
} else {
// ...
const { roles } = await store.dispatch('user/getInfo')
// ...
}
} else {
// ...
}
})
src/store/modules/user.js
这里用其中 getInfo 方法获取用户信息,其中角色返回给 beforeEach
import { login, logout, getInfo } from '@/api/user'
// ...
const actions = {
getInfo({ commit, state }) {
return new Promise((resolve, reject) => {
getInfo(state.token).then(response => {
const { data } = response
if (!data) {
reject('Verification failed, please Login again.')
}
const { roles, name, avatar, introduction } = data
if (!roles || roles.length <= 0) {
reject('getInfo: roles must be a non-null array!')
}
commit('SET_ROLES', roles)
commit('SET_NAME', name)
commit('SET_AVATAR', avatar)
commit('SET_INTRODUCTION', introduction)
resolve(data)
}).catch(error => {
reject(error)
})
})
}
}
src/router/index.js
路由表中路由分成两部分,静态路由与动态路由
export const constantRoutes = [
// ...
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},
{
path: '/',
component: Layout,
redirect: '/dashboard',
children: [
{
path: 'dashboard',
component: () => import('@/views/dashboard/index'),
name: 'Dashboard',
meta: { title: 'dashboard', icon: 'dashboard', affix: true }
}
]
}
// ...
]
动态路由
export const asyncRoutes = [
{
path: '/permission',
component: Layout,
redirect: '/permission/page',
alwaysShow: true, // will always show the root menu
name: 'Permission',
meta: {
title: 'permission',
icon: 'lock',
roles: ['admin', 'editor'] // you can set roles in root nav
},
children: [
{
path: 'page',
component: () => import('@/views/permission/page'),
name: 'PagePermission',
meta: {
title: 'pagePermission',
roles: ['admin'] // or you can only set roles in sub nav
}
},
{
path: 'directive',
component: () => import('@/views/permission/directive'),
name: 'DirectivePermission',
meta: {
title: 'directivePermission'
// if do not set roles, means: this page does not require permission
}
},
{
path: 'role',
component: () => import('@/views/permission/role'),
name: 'RolePermission',
meta: {
title: 'rolePermission',
roles: ['admin']
}
}
]
},
{
path: '/icon',
component: Layout,
children: [
{
path: 'index',
component: () => import('@/views/icons/index'),
name: 'Icons',
meta: { title: 'icons', icon: 'icon', noCache: true, roles: ['admin'] }
}
]
}
// ...
}
src/layout/index.vue
它对应的是我们之前介绍的 Container.vue 完成主页布局的,路由路径是 /
其中又由多部分组成,其中固定不变的是
变化的是中间的 dashboard 部分(AppMain),它由 router-view 配合子路由切换显示
/api/transaction/list
的后台请求报 404,作为练习,把它补充完整https://gitee.com/oauth/authorize?client_id=${client_id}&redirect_uri=${redirect_uri}&response_type=code
https://gitee.com/oauth/token
携带 client_id、client_secret、code,gitee 返回 access_token 给 8080
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有