一、前言
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>
三、總結