登录演示和功能拆解

登录演示和功能拆解

表单基础校验实现

1. 基础双向绑定

复制代码
<template>
    <el-form>
      <el-form-item label="账号">
        <el-input v-model="formData.username" />
      </el-form-item>

      <el-form-item label="密码">
        <el-input v-model="formData.password" />
      </el-form-item>

      <el-form-item>
        <el-checkbox v-model="formData.remember">记住我</el-checkbox>

      </el-form-item>

      <el-form-item>
        <el-button type="primary" class="login_btn">登录</el-button>

      </el-form-item>

    </el-form>

</template>

<script>
export default {
  name: 'Login',
  data() {
    return {
      formData: {
        username: '',
        password: '',
        remember: ''
      }
    }
  }
}

</script>

2. 表单校验配置

  1. 按照业务要求编写校验规则对象(rules)
  1. el-form组件绑定表单对象(model)和规则对象(rules)
  1. el-form-item组件通过prop属性指定要使用的校验规则

表单统一校验实现

业务背景:表单校验部分的触发条件是失焦事件,如果用户打开界面后直接点击登录按钮,校验将失效,所有需要在点击登录按钮时统一对所有表单进行校验

实现思路:通过调用form组件实例对象的validate方法

复制代码
<template>
  <el-form ref="form">
    <el-form-item>
      <el-button type="primary" class="login_btn" @click="doLogin()">登录</el-button>

    </el-form-item>

  </el-form>

</template>

<script>
export default {
  name: 'Login',
  methods: {
    doLogin() {
      this.$refs.form.validate((valid) => {
        if (valid) {
          // TODO
          console.log('登录')
        }
      })
    }
  }
}
</script>

Vuex管理用户Token

业务背景:由于用户数据的特殊性,可能需要在多个模块中进行使用,适合使用Vuex集中管理

开发模式:有关token的所有操作都放到Vuex中做,组件只做一个事儿就是触发action函数

实现步骤:

  1. 根据接口文档封装登录接口
  1. 在vuex中编写user模块的相关代码
  1. 组件中表单校验通过之后提交action

1. 封装登录接口

src/apis/user.js

复制代码
import request from '@/utils/request'

// 登录函数
/**
 * @description: 登录函数
 * @param {*} data { mobile,password}
 * @return {*} promise
 */
export function loginAPI({ username, password }) {
  return request({
    url: '/park/login',
    method: 'POST',
    data: {
      username,
      password
    }
  })
}

utils/request.js

复制代码
const service = axios.create({
  baseURL: 'https://api-hmzs.itheima.net/tj',
  timeout: 5000 // request timeout
})

2. 编写Vuex相关代码

src/store/modules/user.js

复制代码
import { loginAPI } from '@/api/user'
export default {
  namespaced: true,
  state: () => {
    return {
      token: ''
    }
  },
  mutations: {
    setToken(state, token) {
      state.token = token
    }
  },
  actions: {
    async doLogin(ctx, { username, password }) {
      // 1. 调用接口
      const res = await loginAPI({ username, password })
      // 2. 提交mutation
      ctx.commit('setToken', res.data.token)
    }
  }
}

3. 组件中提交action

复制代码
doLogin() {
  this.$refs.form.validate(async(valid) => {
    console.log(valid)
    if (valid) {
      // TODO
      console.log('登录')
      const { username, password } = this.formData
      await this.$store.dispatch('user/doLogin', { username, password })
      this.$router.push('/')
    }
  })
}

用户Token持久化

vuex-persistedstate 是一个 Vuex 插件,它允许你将 Vuex 的状态持久化存储在浏览器的 localStorage 或 sessionStorage 中。这对于需要在页面刷新后保持某些状态非常有用

vuex-persistedstate的工作机制:

  1. 在 mutation 完成对state的更新后,vuex-persistedstate 监听到状态的变化
  2. vuex-persistedstate 将更新后的状态序列化(通常是转换为 JSON 字符串)
  3. 序列化后的数据被保存到指定的持久化存储中(例如 localStorage,sessionStorage中

使用步骤:

  1. npm install vuex-persistedstate 或者 yarn add vuex-persistedstate 安装

  2. 在store/index.js中使用

  3. 登录成功后,观察本地存储中如果有token即为成功

    import Vue from 'vue'
    import Vuex from 'vuex'
    import user from './modules/user'
    import createPersistedState from 'vuex-persistedstate'
    Vue.use(Vuex)

    export default new Vuex.Store({
    plugins: [
    createPersistedState({
    key: 'hm--vuex-token', // 存储在 localStorage 中的键名,默认为 'vuex'
    storage: window.localStorage, // 或者 window.localStorage,默认为 localStorage
    paths: ['user.token'] // 指定要持久化的 state 的路径,默认为所有 state
    })
    ],
    modules: {
    user
    }
    })

Axios请求头中添加Token

  1. 为什么要添加Token到请求头?

点击查看答案接口需要做鉴权,只有token有效,才能返回正常数据,token就是后端用来做判断的标识

  1. 为什么要在axios中加?

点击查看答案项目中有很多接口都需要加鉴权功能,axios请求拦截器可以同一控制,一次添加,多个接口生效```

复制代码
import store from '@/store'

// 添加请求拦截器
request.interceptors.request.use(function (config) {
  // 在发送请求之前做些什么
  const  token  = store.state.user.token
  if (token) {
    config.headers.Authorization = token
  }
  return config
}, function (error) {
  // 对请求错误做些什么
  return Promise.reject(error)
})

记住我功能实现

交互表现:

  1. 如果当前用户选中了checkbox,点击登录之后,再次回到登录,应该把之前输入的用户名和密码回填到输入框里面;
  1. 如果当前用户取消了checkbox,点击登录之后,再次回到登录,应该把之前存到本地的数据清除掉

实现思路:

  1. 完成选择框的双向绑定 得到一个true或者false的选中状态
  1. 如果当前为true,点击登录时,表示要记住,把当前的用户名和密码存入本地
  1. 组件初始化的时候,从本地取账号和密码,把账号密码存入用来双向绑定的form身上
  1. 如果当前用户没有记住,状态为false,点击登录的时候要把之前的数据清空

退出登录功能实现

询问用户是否真的要退出 -> 实现退出登录逻辑 ( 1. 清空当前用户的所有信息 2. 调回到登录页 )

1. 编写清除用户信息mutation

复制代码
  mutations: {
    clearUserInfo(state) {
      // 清除Token
      state.token = ''
    }
  },

2. 提交mutation跳回到登录页

复制代码
 methods: {
    // 退出登录
    logout() {
      this.$store.commit('user/clearUserInfo')
      this.$router.push('/login')
    }
}

Token控制路由跳转

业务背景:如果用户没有登录,不让用户进入到页面中,所以需要通过token的有无来控制路由的跳转

说明:白名单指的是不需要用户登录就可以看到的路由,比如/loigin

编写权限控制逻辑

复制代码
// 导入vuex仓库对象
import store from '@/store'

// 路由守卫
router.beforeEach((to, from, next) => {
  // 登录页面直接放行
  if (to.path === '/login') {
    next()
  } else {
    const token = store.state.user.token
    // 判断是否有token
    if (token) {
      // 放行
      next()
    } else {
      // 跳转回登录页
      next('/login')
    }
  }
})

接口错误统一处理

背景:

  1. 接口报错的时候提示用户到底是哪里错误
  1. 接口数量很多 统一管控 不管哪个接口报错了 都能监控到 而且给出提示

    import { Message } from 'element-ui'

    // 响应拦截器
    service.interceptors.response.use(
    response => {
    return response.data
    },
    error => {
    // 错误统一处理
    Message.error(error.response.data.msg)
    return Promise.reject(error)
    }
    )

    export default service

Token失效处理

业务背景:Token存在一定的有效时间,如果长时间不进行接口访问,Token有可能就失效了,需要我们做统一控制

核心思路:因为我们不知道到底用户实在访问哪个接口的时候发生了Token失效访问,所以需要通过拦截器来做

  1. 跳转到登录页
  1. 清除掉过期Token

    // 响应拦截器
    service.interceptors.response.use(
    response => {
    return response.data
    },
    error => {
    // Token 401处理
    console.dir(error.response.status)
    if (error.response.status === 401) {
    // 1. 跳转到登录
    router.push('/login')
    // 2. 清空用户数据
    store.commit('user/clearUserInfo')
    }
    return Promise.reject(error)
    }
    )

相关推荐
qq43569470110 小时前
Vue04
前端·vue.js
Yeats_Liao11 小时前
Feed流系统设计(三):数据模型与存储设计,从表结构到Redis收件箱
java·javascript·redis
我是真菜11 小时前
彻底理解js中的深浅拷贝
前端·javascript
尽兴-13 小时前
4.1 智能体核心:Agent、Sub-Agent、ReAct、规划执行
前端·javascript·react.js·agent·react·subagent
万物更新_13 小时前
vue框架
前端·javascript·vue.js·笔记
Richar14 小时前
Object.freeze()注意事项
前端·javascript
TA远方14 小时前
【HTML】JavaScript Canvas 图像截取与保存完整指南
前端·javascript·html·canvas·截图·截取
Asize14 小时前
JavaScript 数据类型解析:从 null 与 undefined 的迷思到栈堆内存真相
前端·javascript·面试
LDX前端校草14 小时前
position属性值及用法
前端·javascript·面试
晓131314 小时前
【Cocos Creator 3.x】篇——第四章 子系统
前端·javascript·游戏引擎