一、前言
5、完善功能,首页中如果登录成功之后显示的是图标,没有登录显示的是“注册登录”
二、主要内容
(1)第一步用户输入先提交登录表单信息
这里显示的验证码,在通过异步调用获取到,并且在后端存进session中
(1)前端部分
<!--获取验证码:前端--> <input type="text" maxlength="11" placeholder="验证码" v-model="captcha"> <img class="get_verification" src="http://localhost:4000/captcha" alt="captcha" @click="getCaptcha" ref="captcha">
(2)每次点击的时候获取一个新的图片验证码
// 获取一个新的图片验证码 getCaptcha () { // 每次指定的src要不一样 this.$refs.captcha.src = 'http://localhost:4000/captcha?time='+Date.now() }
(3)发送http://localhost:4000/captcha请求的时候,后台接受到这个请求,并且将当前的这个保存到session中
/* 一次性图形验证码 */ router.get('/captcha', function (req, res) { var captcha = svgCaptcha.create({ ignoreChars: '0o1l', noise: 2, color: true }); req.session.captcha = captcha.text.toLowerCase();//将创建的这个新的验证码保存到session中 console.log(req.session.captcha) /*res.type('svg'); res.status(200).send(captcha.data);*/ res.type('svg'); res.send(captcha.data) });
(1)提交表单的时候触发login()方法,然后调用自己在api/index.js中封装的axios方法
async login () { let result // 密码登陆 const {name, pwd, captcha} = this if(!this.name) { // 用户名必须指定 this.showAlert('用户名必须指定') return } else if(!this.pwd) { // 密码必须指定 this.showAlert('密码必须指定') return } else if(!this.captcha) { // 验证码必须指定 this.showAlert('验证码必须指定') return } // 发送ajax请求密码登陆 result = await reqPwdLogin({name, pwd, captcha}) }
(2)reqPwdLogin方法如下
封装的ajax
import axios from 'axios' export default function ajax(url = '', data = {}, type = 'GET') { return new Promise(function (resolve, reject) { let promise if (type === 'GET') { // 准备url query 参数数据 let dataStr = '' //数据拼接字符串 Object.keys(data).forEach(key => { dataStr += key + '=' + data[key] + '&' }) if (dataStr !== '') { dataStr = dataStr.substring(0, dataStr.lastIndexOf('&')) url = url + '?' + dataStr } // 发送get 请求 promise = axios.get(url) } else { // 发送post 请求 promise = axios.post(url, data) } promise.then(response => { resolve(response.data) }) .catch(error => { reject(error) }) }) }
import ajax from './ajax' const BASE_URL = '/api' //5.根据用户名密码登录 export const reqPwdLogin = ({name, pwd, captcha}) => ajax('/api'+'/login_pwd', {name, pwd, captcha}, 'POST')
(3)执行完第三步之后,会向服务器发送请求,服务器处理post请求
/* 密码登陆 */ router.post('/login_pwd', function (req, res) { const name = req.body.name //将表单提交的数据存下来 const pwd = md5(req.body.pwd) const captcha = req.body.captcha.toLowerCase() console.log('/login_pwd', name, pwd, captcha, req.session) // 可以对用户名/密码格式进行检查, 如果非法, 返回提示信息 if(captcha!==req.session.captcha) { return res.send({code: 1, msg: '验证码不正确'}) } // 删除之前保存的验证码 delete req.session.captcha UserModel.findOne({name}, function (err, user) { if (user) { console.log('findUser', user) if (user.pwd !== pwd) { res.send({code: 1, msg: '用户名或密码不正确!'}) } else { req.session.userid = user._id res.send({code: 0, data: {_id: user._id, name: user.name, phone: user.phone}}) } } else { const userModel = new UserModel({name, pwd}) userModel.save(function (err, user) { // 向浏览器端返回cookie(key=value) // res.cookie('userid', user._id, {maxAge: 1000*60*60*24*7}) req.session.userid = user._id const data = {_id: user._id, name: user.name} // 3.2. 返回数据(新的user) res.send({code: 0, data}) }) } }) })
(4)后台验证成功后需要做两步操作
第一步:将后台返回的user信息保存在vuex的state中去
第二步:实现路由跳转
async login () { let result // 密码登陆 const {name, pwd, captcha} = this if(!this.name) { // 用户名必须指定 this.showAlert('用户名必须指定') return } else if(!this.pwd) { // 密码必须指定 this.showAlert('密码必须指定') return } else if(!this.captcha) { // 验证码必须指定 this.showAlert('验证码必须指定') return } // 发送ajax请求密码登陆 result = await reqPwdLogin({name, pwd, captcha}) // 停止计时 if(this.computeTime) { this.computeTime = 0 clearInterval(this.intervalId) this.intervalId = undefined } // 根据结果数据处理 if(result.code===0) { const user = result.data // 将user保存到vuex的state this.$store.dispatch('recordUser', user) // 去个人中心界面 this.$router.replace('/profile') } else { // 显示新的图片验证码 this.getCaptcha() // 显示警告提示 const msg = result.msg this.showAlert(msg) } }
(1)用vuex来管理状态
state.js中定义userinfo来存放提交成功的用户名和密码
export default{ userInfo:{}//保存提交的用户信息 }
mutation-types.js中定义
export const RECEIVE_USER_INFO = 'receive_user_info'//接受用户信息
mutations.js
/* vuex的mutations.js模块 */ import { RECEIVE_USER_INFO, } from './mutation-types' export default{ //这个是方法名,action 和mutation交互的时候传的是包含这个数据的对象 [RECEIVE_USER_INFO] (state, {userInfo}){ state.userInfo = userInfo } }
actions.js
/* vuex的actions.js模块 */ import { RECEIVE_USER_INFO, } from './mutation-types' //三个接口函数 import { reqUserInfo, } from '../api' export default{ //同步记录用户信息 recordUser ({commit},userInfo){ commit(RECEIVE_USER_INFO,{userInfo}) },
}
(2)在app.vue中用,模块actions中记录的保存用户信息事件,
// 根据结果数据处理 if(result.code===0) { const user = result.data // 将user保存到vuex的state this.$store.dispatch('recordUser', user) // 去个人中心界面 this.$router.replace('/profile') } else { // 显示新的图片验证码 this.getCaptcha() // 显示警告提示 const msg = result.msg this.showAlert(msg) }
(3)登录成功之后显示用户名,实现如下效果
第一步:需要从state中取出保存的userInfo,然后显示在页面中
import {mapState} from 'vuex' export default{ components:{ HeaderTop }, computed:{ ...mapState(['userInfo']) } } </script>
第二步:显示
<!--如果有userInfo信息,这里就显示用户信息,否则就显示注册/登录--> <p class="user-info-top">{{userInfo._id|| '注册|登录'}}</p>
5、完善功能,首页中如果登录成功之后显示的是图标,没有登录显示的是“注册登录”
(1)已登录
(2)未登录
<router-link class="header_login" slot='right' :to="userInfo._id? '/userInfo':'/login'"> <span class="header_login_text" v-if="!userInfo._id">登录注册</span> <span class="header_login_text" v-else> <i class="iconfont icon-geren"></i> </span> </router-link>
session是以赖与cookie的,
一般有两种cookie,一种是会话级别的(当刷新浏览器,或者关闭浏览器之后,在cookie中保存的信息就没有了),一种是持久化的(可以在cookie中将信息保存一段时间)
(1)在后台中设置保存的时间
app.use(session({
secret: '12345',
cookie: {maxAge: 1000*60*60*24 }, //设置maxAge是80000ms,即80s后session和相应的cookie失效过期
resave: false,
saveUninitialized: true,
}));
(2)服务器中会根据session中的userid,查询对应的user
/* 根据sesion中的userid, 查询对应的user */ router.get('/userinfo', function (req, res) { // 取出userid const userid = req.session.userid // 查询 UserModel.findOne({_id: userid}, _filter, function (err, user) { // 如果没有, 返回错误提示 if (!user) { // 清除浏览器保存的userid的cookie delete req.session.userid res.send({code: 1, msg: '请先登陆'}) } else { // 如果有, 返回user res.send({code: 0, data: user}) } }) })
(3)前台最开始肯定要向后台发送一个请求,如果查询到了,当前的用户信息是session中保存的信息,就免登陆
在actions.js模块中添加一个方法
//异步获取用户信息,让应用一开始就调用这个方法 //获取商家列表 async getUserInfo ({commit, state}){ //1.发送异步ajax请求,调用上面那个方法,现在的数据是在state里面 const result = await reqUserInfo() //2.提交一个mutation if(result.code == 0){ const userInfo = result.data commit(RECEIVE_USER_INFO,{userInfo:result.data}) } }
(4)在前台调用这个方法
<script> import FooterGuide from './components/FooterGuide/FooterGuide.vue' import {mapActions} from 'vuex' export default { name: 'App', components:{ FooterGuide }, mounted(){ this.getUserInfo() } , methods:{ ...mapActions(['getUserInfo']) } } </script>
三、总结