登录演示和功能拆解

登录演示和功能拆解

表单基础校验实现

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属性指定要使用的校验规则

    <template> <el-form :model="formData" :rules="rules"> <el-form-item label="账号" prop="username" > <el-input v-model="formData.username" /> </el-form-item>
    复制代码
       <el-form-item
         label="密码"
         prop="password"
       >
         <el-input v-model="formData.password" />
       </el-form-item>
    
       <el-form-item prop="remember">
         <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: '' }, rules: { username: [ { required: true, message: '请输入账号', trigger: 'blur' } ], password: [ { required: true, message: '请输入密码', trigger: 'blur' } ] } } } } </script>

表单统一校验实现

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

实现思路:通过调用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,点击登录的时候要把之前的数据清空

    <script> const FORMDATA_KEY = 'form_key' export default { name: 'Login', mounted() { const cacheFormStr = localStorage.getItem(FORMDATA_KEY) if (cacheFormStr) { const cacheFormData = JSON.parse(cacheFormStr) this.formData.username = cacheFormData.username this.formData.password = cacheFormData.password } }, methods: { doLogin() { this.$refs.form.validate((valid) => { console.log(valid) if (valid) { // TODO console.log('登录') const { username, password, remember } = this.formData this.$store.dispatch('user/doLogin', { username, password })
    复制代码
             // 补充remeber逻辑
             if (remember) {
               localStorage.setItem(FORMDATA_KEY, JSON.stringify({ username, password }))
             } else {
               localStorage.removeItem(FORMDATA_KEY)
             }
           }
         })
       }
     }

    }

    </script>

退出登录功能实现

询问用户是否真的要退出 -> 实现退出登录逻辑 ( 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)
    }
    )

相关推荐
Hilaku19 分钟前
我用 Gemini 3 Pro 手搓了一个并发邮件群发神器(附源码)
前端·javascript·github
全栈前端老曹31 分钟前
【包管理】npm init 项目名后底层发生了什么的完整逻辑
前端·javascript·npm·node.js·json·包管理·底层原理
HHHHHY37 分钟前
mathjs简单实现一个数学计算公式及校验组件
前端·javascript·vue.js
boooooooom40 分钟前
Vue3 provide/inject 跨层级通信:最佳实践与避坑指南
前端·vue.js
一颗烂土豆40 分钟前
Vue 3 + Three.js 打造轻量级 3D 图表库 —— chart3
前端·vue.js·数据可视化
iReachers44 分钟前
HTML打包APK(安卓APP)中下载功能常见问题和详细介绍
前端·javascript·html·html打包apk·网页打包app·下载功能
沉静的思考者1 小时前
vue优雅的适配无障碍
vue.js
愈努力俞幸运1 小时前
vue3 demo教程(Vue Devtools)
前端·javascript·vue.js
持续前行1 小时前
在 Vue3 中使用 LogicFlow 更新节点名称
前端·javascript·vue.js
Anita_Sun1 小时前
Underscore.js 整体设计思路与架构分析
前端·javascript