前端工程化开发-登录全流程 Vue

102 阅读3分钟

1、进入首页之前在登录页面 login.vue 先将表单数据放到一个函数中,方便打包发请求,然后进行表单校验

// element-ui 表单校验

{ required: true, message: '不能为空', trigger: 'blur' },
{ pattern: /^(?:(?:\+|00)86)?1\d{10}$/, message: '手机号不合法', trigger: ['blur', 'change'] }

==================================================

// 打包的函数
loginForm: {
        mobile: '',
        password: '',
        isAgree: false
      }

========================================
 // 兜底校验
      this.$refs.form.validate((valid) => {
        valid && this.doLogin()
      })

进入到 user.js 公共仓库,在公共仓库中, actions 内发送异步请求,得到数据(包含 token)后由 mutationsn 将 token 赋值给 state

在这里还将token 存储到了本地

token 也可以称为令牌或者钥匙,有了 token 才能在网页的宫殿中通行

//
const state = {
  token: getToken() || ''
}

const mutations = {
  // 修改 token
  alterToken(state, newToken) {
    state.token = newToken

  //存储到本地
    setToken(state.token)
  },
  }

const actions = {
  // 登录
  async login(context, payload) {
    const res = await login(payload)
    const token = res.data
    context.commit('alterToken', token)

    console.log(res.data)
  }
  }

本地存储封装在 utils/auth.js ,模块化开发复用性更高、可以更好的代码组织和管理,开发效率也会更高

token 的名字尽量长一点,以免被覆盖

// token 的操作
import Cookies from 'js-cookie'

// token 名
const TokenKey = '230516-vue-lbh-rz-token'

// 存储
export function getToken() {
  return Cookies.get(TokenKey)
}
// 获取
export function setToken(token) {
  return Cookies.set(TokenKey, token)
}
// 删除
export function removeToken() {
  return Cookies.remove(TokenKey)
}

发请求的流程繁琐,且复用性极差,可以单独封装一个 api 组件,在使用时可以直接调用 api/user.js 文件

// 登录请求
export const login = data => request.post('/sys/login', data)

在发送请求时的优化方案,配置基地址,同时处理请求超时的问题 在 utils/request.js 文件中

超时的处理尽量不要太长,否则用户体验就不太好了,单位是毫秒(ms),我现在设置的就是 5 秒(s)

// 请求基地址
const request = axios.create({
  baseURL: '/api',
  timeout: 5000
})

发送请求给服务器后,服务器会响应给你数据,在这中间的流程中,也有一些要问题需要处理,在这里使用 axios 来完成请求拦截器和响应拦截器

请求拦截器中,在发送请求之前给每一个请求添加 token ,具体格式根据接口文档来写,if 判断一下有 token 才加,这个是必要的

响应拦截器中,处理获取到的表单数据是否符合你的预期,如果符合就返回数据,不符合则在此处单独处理,在响应拦截器成功和错误两个函数中都是类似操作
例如:失败提示给用户

千万不要忘记导出

// 添加请求拦截器
request.interceptors.request.use(function(config) {
  // 在发送请求之前做些什么

  // 获取token
  const token = store.state.user.token
  // 在每个请求中加入 token
  if (token) {
    console.log(token)
    config.headers.Authorization = `Bearer ${token}`
  }
  return config
}, function(error) {
  // 对请求错误做些什么
  return Promise.reject(error)
})



// 响应拦截器
request.interceptors.response.use((response) => {
  // 响应成功
  // 判断操作是否正确
  if (response.data.success) {
    return response.data
  } else {
    // 错误处理
    // 提示用户
    Message.error(response.data.message)
    // 设置返回值
    return Promise.reject(response.data.message)
  }
  // return response
}, (error) => {
  // 响应失败
  // 处理token 失效
  if (error.response.status === 401) {
    // 提示给用户
    Message.error('请登录')
    // 清空本地 token
    store.dispatch('user/login')
    // 强制跳转
    router.push('/login')
  }
  return Promise.reject(error)
})

// 导出
export default request

发送请求成功且无误的到达服务器之后,服务器响应数据,将以上流程倒叙执行一遍,在最后是返回给 公共空间的 actions 处理,处理后,就可以将数据在浏览器内使用或渲染给即将要跳转的首页中

2、当点击登录时,需要提交在 login.vue 中校验过的表单,怎么提交? 通过 dispatch 提交给公共仓库

// 异步
 await this.$store.dispatch('user/login', this.loginForm)

3、成功后跳转到首页

跳转到首页,就像刚刚说的,进入宫殿需要令牌,那么怎么验证你有没有令牌,或者说由谁来验证? 在宫殿中也会有一些开放区域,供游客浏览,开放区域则不需要令牌,但是怎么识别哪里是开放区域,哪里是只有令牌才能进入的区域呢? 做这些事情的就是导航守卫(路由的前置导航守卫),在这里处理 token 为空,和白名单的放行

在路由守卫中需要判断请求有没有携带 token ,如果携带则放行,没有携带则强制跳转到登录页面,白名单区域则可以随意浏览

在这里额外添加了进度条样式,提高用户体验

注意在放行即进入主页之前,发请求了获取用户信息详情,方便后续操作


// 进度条
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style

// 白名单
const whiteList = ['/login', '/404']
// 路由导航守卫
router.beforeEach(async(to, from, next) => {
  // 开启进度条
  NProgress.start()

  // 获取 token
  const token = store.state.user.token
  console.log('beforeEach', token)

  // 判断
  if (token) {
    // 单独处理登录跳转
    if (to.path === '/login') {
      next('/')
      // 解决进度条卡顿问题,手动关闭
      NProgress.done()
    } else {
      // 在进入主页之前。发请求获取用户信息
      // store.dispatch('user/getProfile')
      
      if (store.getters.userId) { await store.dispatch('user/getProfile') }

      next()
    }
    next()
  } else {
    // 判断去哪里
    if (whiteList.includes(to.path)) {
      next()
    } else {
      Message.error('未登录')
      // 强制跳转
      next('/login')
      // 解决进度条卡顿问题,手动关闭
      NProgress.done()
    }
  }
})

// 结束进度条
router.afterEach(() => {
  // finish progress bar
  NProgress.done()
})