基于Vue2+Vuex+VAT实现用户登录的简单模板-自我学习笔记


本文所有的功能实现仅展示关键代码片段,标签中的placeholder、tabindex和样式等非主干部分均略去。

表单校验(以手机号-密码为例)

基于el-form表单进行校验数据与属性配置

el-form

el-form:负责绑定 model(表单数据对象) 和 rules(校验规则对象),key必须得统一
el-form-item: 负责绑定prop (校验规则的key名)
el-input: 负责双向绑定具体的表单数据 (表单数据的key名)

<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
	<el-form-item prop="mobile">
		<el-input ref="mobile" v-model="loginForm.mobile"
		 name="mobile" type="text"
		 />
	</el-form-item>
	<el-form-item prop="password">
        <el-input :key="passwordType" ref="password"
          v-model="loginForm.password"
          name="password" :type="passwordType"
          @keyup.enter.native="handleLogin"
        />
      </el-form-item>
</el-form>

导入自定义校验规则函数

export function validMobile(phone) {
  // 根据具体校验规则编写正则表达式,并返回结果
  return /^1[3-9]\d{9}$/.test(phone)
}

表单数据对象与校验规则对象

import { validMobile } from '@/utils/validate' // 需要复杂数据校验时从外部导入
data() {
  return {
  	// 定义校验手机号的箭头函数
	const validateMobile = (rule, value, callback) => {
	  if (!validMobile(value)) { // 
	    callback(new Error('请输入正确的手机号'))
	  } else {
        callback()
      }
    }
	// 表单数据对象 和 校验规则对象
	loginForm: {
	  mobile: '13400000001',
      password: '123456'
	},
    loginRules: {
      mobile: [{ required: true, trigger: 'blur', validator: validateMobile }], // 调用校验
      password: [{ required: true, trigger: 'blur', min: 6, max: 16, message: '密码长度必须在6-16位之间' }]
	}
  }
}

登录方法处理与登录调用

methods: {
  showPwd() { // 功能:点击切换密码的显示模式:数字还是远点
	if (this.passwordType === 'password') {
	  this.passwordType = ''
    } else {
      this.passwordType = 'password'
    }
    this.$nextTick(() => { // 使用Element自带的输入框focus事件,使input框获取焦点
      this.$refs.password.focus()
    })
  },
  handleLogin() {
	this.$refs.loginForm.validate(async valid => { // 表单校验
	  if (valid) {
		try {
		  // 避免单组件功能堆积,使用Vuex,通过dispatch调用user模块中actions中的登录API
          this.$store.dispatch('user/loginActions', this.loginForm)
        } catch (err) { // 错误对象用dir打印
          console.dir(err)
        }
      }
    })
  },
}

Vuex

state-初始化Token状态

const state = () => ({
  token: '' // 用户 Token,默认为 ''
})

mutations-提供操作Token的方法

const mutations = {
  // ...其他
  // 设置token
  SET_TOKEN(state, newToken) {
    state.token = newToken
  },
  // 删除token
  REMOVE_TOKEN(state) {
    state.token = ''
  }
}

actions-调用登录请求接口等异步方法

const actions = {
  async loginActions({ commit }, data) {
    const res = await loginAPI(data)
    commit('SET_TOKEN', res.data) // 在Vuex和浏览器存储Token
  }
}

接口调用

export function loginAPI(data) {
  return request({
    url: '/sys/login', // 以自己对接的后端接口为准
    method: 'POST',
    // axios内部会默认携带请求头Content-Type: 'application/json'
    // Content-Type: 'application/json' -> 请求体中的参数名和值会变成JSON字符串格式给后台
    data
  })
}

Token处理

axios请求拦截器-统一注入

  • 如果当前 vuex中有 token,就在请求头中设置上
  • (如果后端有规定)因为后端返回的 token 没有添加上 Bearer 字符串,因此需要手动添加,Authorization 和 Bearer 是本文后端接口要求的写法。
import store from '@/store'

service.interceptors.request.use(
  config => {
    // js文件中不能使用this.$store,因为这个this关键字不是Vue组件对象, 无法查找原型链上$store
    // 但是this.$store为了拿到的是store/index.js导出store对象
    // 解决: 直接把store对象导入过来使用, 是同一个store对象
    const token = store.getters.token
    if (token) {
      config.headers.Authorization = `Bearer ${token}`
    }
    return config
  },
  error => {
    return Promise.reject(error)
  }
)

Token的持久化

现在 token 虽然保存在 vuex 中,但页面刷新之后,vuex 的内容丢失了,将会导致接口访问异常。所以我们需要对 token 做持久化处理,让页面刷新之后 token 不丢失。

  • 在设置 token 的时候除了在 vuex 中存一份,在本地也同步存一份
  • 在对 token进行初始化的时候先从本地取一下,优先使用本地取到的值
  • 在删除 token 的时候除了把 vuex 中的删除掉,把本地的也一并删除
const mutations = {
  RESET_STATE: (state) => {
    Object.assign(state, getDefaultState())
  },
  // 设置token
  SET_TOKEN(state, newToken) {
    state.token = newToken
    setToken(newToken)
  },
  // 删除token
  REMOVE_TOKEN(state) {
    state.token = ''
    removeToken()
  }
}

一些关于Vuex、Token和网络请求的问题

1.Token的作用是什么?

(1)判断用户是否登录:如果有token,说明登录过(即便已经过期),能看到登录才能看到的页面
否则,只会放行登录和注册页面,其他页面会被强制next切换到登录注册页面

(2)前端如果携带过期token给后端,后端验证过期后返回401,进入响应拦截器在响应拦截器里写判断代码,如果401了就退出登录

(3)axios请求拦截器将token值添加在请求头中,任意一次请求都会执行

2.为什么不直接使用本地的token, 还要使用vuex里的呢?

  • 其实可以直接使用本地的token, 不使用vuex的
  • 浏览器本地的token, 是要进行磁盘数据的读取和写入, 速度没有vuex快
  • 但是vuex是在内存里, 虽然快, 但是刷新就消失了, 所以要在本地持久存储同步一份
  • 如果面试的时候, 遇到抬杠的, 我们就直接都从本地存取吧, 反正也不差那点时间(很快)

3.Vuex各部分的作用是什么?

store只能是唯一的,state里定义全局状态变量

mutations里唯一同步修改state里的值

  • $store.commit('要触发的mutations函数名')出来mutations里的函数执行

actions里定义异步代码(一般调用后端接口,并把值commit给mutations)

  • $store.dispatch('要触发的actions函数名')触发actions里的函数执行
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值