总结一下今天在项目中完成的功能
手机验证码登录功能
用到的前端技术:vue、vuex、axios,element-ui组件库
功能实现总体思路:
一. 用户在登录界面输入手机号,通过表单验证后,点击按钮获取验证码
二. 用户输入手机验证码,再次进行校验,然后点击登录按钮进行登录
三. 向后台发起数据请求,等待后台返回结果,这一步有两件事要做:
1.发请求之前,对axios进行封装,配置基础请求路径、请求时长、默认post请求头,设置请求响应拦截器
2.如果请求响应成功,对后台返回用户登录的token和用户信息进行存储(存到本地)
3.如果请求响应失败,提示错误信息
四.拿到数据之后,对数据进行页面渲染
五.退出登录,清除token和用户信息
一、用户在登录界面输入手机号,通过表单验证后,点击按钮获取验证码 二. 用户输入手机验证码,再次进行校验,然后点击登录按钮进行登录
- 登录界面使用element-ui的el-form表单校验
<el-formclass="phone-form"ref="form":model="form"label-position="left"size="small":rules="rules"><el-form-itemprop="phoneNum"><el-inputsize="small"placeholder="请输入手机号"v-model="form.phoneNum"class="input-with-select"><el-select v-model="select" slot="prepend" placeholder="+86"><el-option label="+86" value="+86"></el-option><el-option label="+40" value="+86"></el-option><el-option label="+111" value="+86"></el-option></el-select></el-input></el-form-item><el-form-itemprop="checkCode"><el-inputclass="check-code-box"size="small"v-model.number="form.checkCode"placeholder="请输入验证码"><el-button size="small" slot="append" @click="handleCaptcha">获取验证码</el-button></el-input></el-form-item><el-form-item><el-button class="custom-button" @click="onSubmit('form')" type="primary">登录</el-button></el-form-item></el-form>
- 验证规则
data () {return {rules: {phoneNum: [{ required: true, message: '手机号码不能为空哦!', trigger: 'blur' },{ min: 11, message: '请输入11位手机号码', trigger: 'blur' }],checkCode: [{ required: true, message: '验证码不能为空哦!', trigger: 'blur' }]}}},methods: {// 验证手机格式validatePho (value, callback) {if (value.toString().length < 11) {callback(new Error('手机号输入不正确'))}}}
- 获取验证码
// 获取手机验证码handleCaptcha () {captcha(this.form.phoneNum)}
三. 向后台发起数据请求,等待后台返回结果 四.拿到数据之后,对数据进行页面渲染
- 发请求之前,对axios进行封装,配置基础请求路径、请求时长、默认post请求头,设置请求响应拦截器
import axios from 'axios'
import store from '@/store/index'
import { Loading } from 'element-ui'// 对axios进行封装
const request = axios.create({baseURL: '/api',timeout: 10000
})
// 设置post请求默认请求头
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'
// loading进度样式
const options = {lock: true,background: 'rgb(0, 0, 0, 0.8)',text: 'Loading'
}// 在请求之前拦截
request.interceptors.request.use(function (config) {Loading.service(options)// 每次发送请求之前判断vuex中是否存在token// 如果存在,则统一在http请求的header都加上token,这样后台根据token判断你的登录情况// 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断const token = store.getters.getTokenif (token) {// 已经登录成功,统一添加tokenconfig.headers.Authorization = `Bearer ${token}`}return config},function (error) {if (error.response.status) {// 判断错误类型(状态码)switch (error.response.status) {// 401: 未登录// 未登录则跳转登录页面,并携带当前页面的路径// 在登录成功后返回当前页面,这一步需要在登录页操作。case 401:this.$message({type: 'info',customClass: 'model-message',iconClass: '1',message: '未登录'})break// 403 token过期// 登录过期对用户进行提示// 清除本地token和清空vuex中token对象case 403:this.$message({type: 'info',customClass: 'model-message',iconClass: '1',message: '未登录'})break// 404请求不存在case 404:this.$message({message: '网络请求不存在',duration: 1500,type: 'success'})break// 其他错误,直接抛出错误提示default:this.$message({message: error.response.data.message,duration: 1500,type: 'success'})}// 对请求错误进行操作return Promise.reject(error)}}
)// 在请求之后拦截
request.interceptors.response.use(function (response) {if (response.status === 200) {// 对响应数据进行操作Loading.service(options).close()return Promise.resolve(response)} else {return Promise.reject(response)}},function (error) {// 对响应错误进行操作return Promise.reject(error)}
)export default request
- 如果请求响应成功,对后台返回用户登录的token和用户信息进行存储,这里用vuex对token和用户信息进行管理,而且要进行持久化,不然页面一刷新数据就没有了
import Vue from 'vue'
import Vuex from 'vuex'
import createPersistedState from 'vuex-persistedstate'Vue.use(Vuex)const state = {// 存储tokentoken: '',// 当前用户基本信息userInfo: ''
}const getters = {// 获取tokengetToken (state) {return state.token || localStorage.getItem('token') || ''}
}const mutations = {// 设置tokenSETTOKEN (state, token) {state.token = token// 存储tokenlocalStorage.setItem('token', token)},// 删除tokenDELTOKEN (state) {state.token = ''localStorage.removeItem('token')},// 更新用户信息UPDATEUSERINFO (state, value) {state.userInfo = value},// 删除用户信息DELETEUSERINFO (state) {state.userInfo = ''localStorage.removeItem('userInfo')}
}export default new Vuex.Store({// 本地缓存(持久化)PersistedStateplugins: [createPersistedState({reducer: (state) => {return {songInfo: state.songInfo,songUrl: state.songUrl,model: state.model,renList: state.renList,songIndex: state.songIndex,userInfo: state.userInfo}}})],state,getters,mutations
})
- 在点击按钮的时候,进行整改表单的校验,如果校验成功,发送手机号和验证码给后台,如果请求响应失败,提示错误信息 (错误信息的提示我用到了element-ui的Message样式组件)
computed: {...mapState({// 登录凭证token: 'token'})
},
methods: {...mapMutations({// 存储tokensetToken: 'SETTOKEN',// 更新用户信息updateUserInfo: 'UPDATEUSERINFO'}),// 手机验证码登录async onSubmit (form) {this.$refs[form].validate(async (valid) => {if (valid) {await cellphone(this.form.phoneNum, this.form.checkCode).then(res => {console.log(res)// 存储tokenthis.setToken(res.data.token)// 存储用户信息this.updateUserInfo(res.data.profile)this.$message({type: 'info',customClass: 'model-message',iconClass: '1',message: '登录成功'})// 通知父组件显示用户名this.$emit('isActive')}).catch(error => {this.$message({type: 'info',customClass: 'model-message',iconClass: '1',message: error})})} else {console.log('error submit!!')return false}})}
}
- 渲染数据,用到了element-ui的下拉菜单组件、头像组件
<div class="container"><div class="login-box"><el-dropdownv-if="isActive"class="custom-el-dropdown"@command="handleCommand"><span class="el-dropdown-link hidden-xs-only"><el-avatar v-if="userInfo" size="medium" :src="userInfo.avatarUrl"></el-avatar><div class="nickname">{{ userInfo.nickname }}<i class="el-icon-arrow-down el-icon--right"></i></div></span><el-dropdown-menu slot="dropdown"><el-dropdown-item command="mineHomepage">我的主页</el-dropdown-item><el-dropdown-item command="minePlayList">我的歌单</el-dropdown-item><el-dropdown-item command="logOut">退出登录</el-dropdown-item></el-dropdown-menu></el-dropdown><el-buttonv-elsetype="text"@click="handleDialogForm()"class="custom-login">登录</el-button></div>
五.退出登录,清除token和用户信息
// 下拉菜单事件async handleCommand (command) {switch (command) {// 退出登录case 'logOut':await logout().then(res => {// 清除tokenthis.delToken()// 清除用户信息this.deleteUserInfo()// 是否显示用户名this.handleUserName()this.$message({type: 'info',customClass: 'model-message',iconClass: '1',message: '注销成功'})}).catch(err => {console.log(err)})break// 获取我的歌单case 'minePlayList':this.minePlayList()break// 我的主页case 'mineHomepage':break}
登录成功效果:
这功能的实现离不开大佬的手把手教懂,通过学习大佬的下面的文章,我才能顺利完成我的功能。
文章链接:前端老实人