Uni-app 手机号+验证码登录 & 用户名密码登录登出
mine.vue > mine (tab页) 在此页面点击登陆跳转到login.vue<template><view class="mine"><u-navbar :is-back="false" :background="background" :border-bottom="false"><view slot="right"><vie
·
- 用户名密码登录,手机号登录
- 用户名密码登录:用了uniapp+uview的$u.debounce防抖方法,再发送请求
- 判断正则以及同意条款勾选后,发起登录请求(参数是用户名和密码),如果请求成功——setStorage存储aes加密了的token,同时跳转页面回到主页mine.vue
- 在mine.vue主页中,onShow中判断:如果现在有存储的token了,但是vuex中没有用户信息,就调用getUserInfo方法——发起获取用户信息的请求(请求头中带着解密的token),如果请求成功——将请求到的用户信息存储到vuex中,并在页面中渲染及使用
- 在App.vue中, onLaunch判断(重新打开app时,vuex已经销毁了):如果现在有存储的token(永久的,必然有),就调用getUserInfo方法,存到vuex中。目的:只要曾经登录过,重启App时,不进入mine.vue,也方便用户的学习、购买等操作
mine.vue > mine (tab页) 在此页面点击登陆跳转到login.vue
<template>
<view class="mine">
<u-navbar :is-back="false" :background="background" :border-bottom="false">
<view slot="right">
<view class="right-content">
<view class="right-setup iconfont icon-shezhi"></view>
<view class="right-sweep iconfont icon-saoyisao"></view>
</view>
</view>
</u-navbar>
<!-- 登录状态 -->
<view class="mine-header" v-if="isLogin">
<view class="mine-img" @tap="goProfile">
<!-- /static/me/avatar.jpeg -->
<image mode=""></image>
</view>
<view class="mine-right">
<view class="login">
{{userInfo.nickName}}
<image :src="userInfo.avatar" mode=""></image>
</view>
<view class="tip" @tap="goProfile">编辑资料</view>
</view>
</view>
<!-- 未登录状态 -->
<view class="mine-header" v-else>
<view class="mine-img">
<image src="/static/me/avatar.png" mode=""></image>
</view>
<view class="mine-right" @tap="goLogin">
<view class="login">点击登陆</view>
<view class="tip">登陆后同步数据,学习更放心</view>
</view>
</view>
<view class="mine-content">
<Member></Member>
<!-- <MeList></MeList> -->
<u-cell-group :border-top="false" class="list-top">
<u-cell-item title="购物车" @tap="goCart()" :title-style="title">
<view slot="icon" class="slot-icon iconfont icon-gouwuche"></view>
</u-cell-item>
<u-cell-item title="我的订单" @tap="goOrder()" :title-style="title">
<view slot="icon" class="slot-icon iconfont icon-dingdan"></view>
</u-cell-item>
<u-cell-item title="电子兑换码" @tap="goChange()" :title-style="title">
<view slot="icon" class="slot-icon iconfont icon-liwu"></view>
</u-cell-item>
</u-cell-group>
<u-cell-group class="list-top">
<u-cell-item title="关于我们" @tap="goAbout()" :title-style="title">
<image slot="icon" src="/static/me/small.png" mode="" class="slot-image"></image>
</u-cell-item>
</u-cell-group>
<!-- 退出登录 -->
<view class="logout" @tap="loginOut">退出登录</view>
</view>
<u-toast ref="uToast" />
<tabbar currentPath="mine"></tabbar>
</view>
</template>
<script>
import Tabbar from '@/common/tabbar/index.vue'
import Member from '@/components/me/Memebar-nav.vue';
import api from '@/service/mine.js'
import {
mapState,
mapActions
} from 'vuex'
export default {
data() {
return {
background: {
backgroundColor: '#f5f5f5'
},
isLogin: false,
title: {
color: '#333'
},
}
},
onShow() {
uni.hideTabBar();
//每次进入页面判断是否已有用户信息
if(uni.getStorageSync('token')){//前提存了token
if (!this.userInfo) {//如果vuex没有用户信息 就发起请求获取用户信息存进vuex
this.getUserInfo();
}else{//如果vuex有用户信息 就显示登录状态
this.isLogin = true
}
}else{//前提没存token
this.isLogin = false
}
},
components: {
Tabbar,
Member
},
computed: {
...mapState({
userInfo: state => state.user.userInfo
})
},
methods: {
...mapActions(['changeUserInfoActions']),
//如果现在有token(token是登录成功后存储的)了,就发起获取用户信息的请求,并将用户信息存储到vuex中
getUserInfo() {
api.getUserInfo().then(res => {
//console.log(res)
if (res.meta.code === '200') {
this.isLogin = true //变成已登录状态
let info = res.data.data
//若有昵称和头像,就走你的昵称和头像;若没有,就走默认的
info.nickName = info.nickName ? info.nickName : '默认昵称'
info.avatar = info.avatar ? info.avatar : '/static/me/avatar.jpeg'
//将用户信息存储到vuex中
this.changeUserInfoActions(info)
} else {
this.$refs.uToast.show({
title: res.meta.msg,
type: 'warning',
icon: false
})
}
}).catch(err => {
console.log(err)
this.$refs.uToast.show({
title: err.meta.msg,
type: 'error',
icon: false
})
})
},
goCart() {
console.log('我的购物车被点击了')
},
goOrder() {
console.log('我的订单被点击了')
},
goChange() {
console.log('电子兑换码被点击了')
},
goAbout() {
console.log('关于我们被点击了')
},
goLogin() {
uni.redirectTo({
url: '../login/login'
})
},
//退出登录
loginOut() {
api.getlogout().then(res => {
if (res.meta.code === '200') {
this.$refs.uToast.show({
title: '退出登录成功',
type: 'success'
})
//清空vuex中用户信息数据
this.changeUserInfoActions()
//移除token
uni.removeStorageSync('token')
this.isLogin = false
}
})
},
//个人资料
goProfile() {
uni.navigateTo({
url:'../profile/profile'
})
}
}
}
</script>
mine.js > 接口
import $http from './request.js'
import {Decrypt} from'@/utils/aes/aes.js'
export default {
//获取用户信息
getUserInfo() {//拿到对象中mobile对应的值
return $http.request({
url: '/member/getInfo',
method: 'GET',
header:{
"Content-Type": "application/json",
"Authorization": Decrypt(uni.getStorageSync('token'))
}
})
}
}
login.vue > 登录页 此页面点击手机登陆跳转到code.vue
<template>
<view class="wrap">
<view class="top"></view>
<view class="content">
<view class="content-header">
<image src="/static/login/logo.png"></image>
<view class="title">欢迎登录</view>
</view>
<block v-if="isPhone">
<input class="u-border-bottom" type="number" v-model="tel" placeholder="请输入手机号" />
</block>
<block v-else>
<input class="u-border-bottom" v-model="username" placeholder="请输入用户名" type="username" />
<input class="u-border-bottom" v-model="password" placeholder="请输入密码" type="password" />
</block>
<view class="alternative">
<u-checkbox-group>
<u-checkbox v-model="checked" shape="circle">
<view class="">
我已阅读并同意<text class="link">用户服务条款</text>和<text class="link">隐私政策</text>
</view>
</u-checkbox>
</u-checkbox-group>
<u-toast ref="uToast" />
</view>
<button @tap="phoneSubmit" :style="[inputStyle]" class="getCaptcha" v-if="isPhone">获取短信验证码</button>
<button @tap="userSubtmit" :style="[inputUserStyle]" class="getCaptcha" v-else>登录</button>
<view class="alternative">
<view class="password"></view>
<view class="issue" @tap="goChange">{{tips}}</view>
</view>
</view>
</view>
</template>
<script>
import {
Encrypt
} from '../../utils/aes/aes.js'
import api from '@/service/login.js'
export default {
data() {
return {
isPhone: true, //手机登录
tel: '',
checked: false, //同意条款
username: '',
password: '',
tips: '用户名密码登录'
}
},
computed: {
inputStyle() {
let style = {};
if (this.tel) {
style.color = "#fff";
style.backgroundColor = 'rgba(51,122,255,1)'
}
return style;
},
inputUserStyle() {
let style = {};
if (this.username && this.password) {
style.color = "#fff";
style.backgroundColor = 'rgba(51,122,255,1)'
}
return style;
}
},
methods: {
//提交手机号登录
phoneSubmit() {
if (this.checked) { //如果勾选同意
let reg = /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/
if (this.$u.test.mobile(this.tel) && reg.test(this.tel)) { //输入的是手机号
this.$u.route({
url: 'pages/login/code',
params: {
tel: Encrypt(this.tel)
}
})
} else { //输入不是手机号
this.$refs.uToast.show({
title: '手机号填写有误',
type: 'warning'
})
}
} else { //没有勾选同意
this.$refs.uToast.show({
title: '请先阅读用户服务条款与隐私政策',
type: 'warning'
})
}
},
goChange() {
if (this.isPhone) { //现在为手机登录
this.isPhone = false;
this.tips = '手机号登录'
} else { //现在为密码登录
this.isPhone = true;
this.tips = '用户名密码登录'
}
},
//提交用户名登录 防抖
userSubtmit() {
if (this.username && this.password) {
this.$u.debounce(this.userLogin, 500)
} else {
this.$refs.uToast.show({
title: '用户名或密码不能为空',
type: 'warning',
icon: false
})
}
},
userLogin() {
if (this.checked) { //如果已勾选
api.loginByJson({
username: this.username,
password: this.password
}).then(res => {
console.log(res)
if (res.meta.code === '10006') {
//存储token
uni.setStorageSync('token', Encrypt(res.data.accessToken))
//跳转页面
uni.switchTab({
url: '../mine/mine'
})
} else {
this.$refs.uToast.show({
title: '登录失败',
type: 'warning',
icon: false
})
}
}).catch(err => {
this.$refs.uToast.show({
title: err.meta.msg,
type: 'error',
icon: false
})
})
}
}
}
};
</script>
code.vue > 输入验证码页面
<template>
<view class="wrap">
<view class="key-input">
<view class="title">输入验证码</view>
<view class="tips">验证码已发送至 +{{showTel}}</view>
<u-message-input :focus="true" :value="value" @finish="finish" mode="bottomLine"
:maxlength="maxlength"></u-message-input>
<text :class="{ error: error }">验证码错误,请重新输入</text>
<view class="captcha">
<!-- -->
<!-- <text :class="{ noCaptcha: show }" @tap="noCaptcha">收不到验证码点这里</text> -->
<text :class="{ regain: !show }">{{ second }}秒后重新获取验证码</text>
</view>
</view>
<u-toast ref="uToast" />
</view>
</template>
<script>
import {
Decrypt,
Encrypt
} from '@/utils/aes/aes.js'
import api from '@/service/login.js'
export default {
data() {
return {
maxlength: 6,
value: '',
second: 60,
show: false,
error: false,
mobile: null
};
},
computed: {
showTel() {
let reg = /^(\d{3})\d{4}(\d{4})$/;
return this.mobile.replace(reg, "$1****$2");
}
},
onLoad(params) {
this.mobile = Decrypt(params.tel) //将手机号解密
this.loginCaptcha() //调用发送短信验证码功能
let interval = setInterval(() => {
this.second--;
if (this.second <= 0) {
this.show = true;
if (this.value.lenth != 6) {
this.error = true;
}
clearInterval(interval);
}
}, 1000);
},
methods: {
//发送短信验证码
loginCaptcha() {
api.sendRegisterOrLoginCaptcha({
mobile: this.mobile
}).then(res => {
if (res.meta.code !== 200) {
this.$refs.uToast.show({
title: res.meta.msg,
type: 'error',
icon: false
})
} else {
this.$refs.uToast.show({
title: '发送成功,留意短信',
type: 'success',
icon: false
})
}
}).catch(err => {
this.$refs.uToast.show({
title: err.meta.msg,
type: 'error',
icon: false
})
})
},
//输入完验证码最后一位执行
finish(value) {
api.loginByMobile({
mobile: Encrypt(this.mobile), //传加密的手机号
captcha: value
}).then(res => {
if (res.meta.code !== '10006') {
console.log(res)
this.$refs.uToast.show({
title: res.meta.msg,
type: 'warning',
icon: false
})
} else {
//登录成功
//存储token
uni.setStorageSync('token', Encrypt(res.data.accessToken))
//跳转页面
uni.switchTab({
url: '../mine/mine'
})
}
}).catch(err => {
this.$refs.uToast.show({
title: err.meta.msg,
type: 'error',
icon: false
})
})
}
}
};
</script>
login.js 接口
import $http from './request.js'
import {
Decrypt
} from '@/utils/aes/aes.js'
export default {
//发送短信验证码
sendRegisterOrLoginCaptcha({mobile}) {//拿到对象中mobile对应的值
return $http.request({
url: '/sms/sendRegisterOrLoginCaptcha?mobile='+mobile,
method: 'GET'
})
},
//手机验证码登录
loginByMobile(params) {//
return $http.request({
url: '/u/loginByMobile',
method: 'POST',
data:params
})
},
//用户名密码登录
loginByJson(params) {//
return $http.request({
url: '/u/loginByJson',
method: 'POST',
data:params
})
},
}
App.vue
<script>
import api from '@/service/mine.js'
import {
mapActions
} from 'vuex'
export default {
onLaunch: function() {
console.log('App Launch')
//前提:曾经登录过 目的:重启时,不进入mine.vue,也能获取用户信息,存储到vuex中,方便该用户的学习、购买等操作
if (uni.getStorageSync('token')) {
this.getUserInfo()
}
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
},
methods: {
...mapActions(['changeUserInfoActions']),
//如果现在有存储的token(代表登录成功过),就发起获取用户信息的请求,并将用户信息存储到vuex中
getUserInfo() {
api.getUserInfo().then(res => {
//console.log(res)
if (res.meta.code === '200') {
this.isLogin = true //变成已登录状态
let info = res.data.data
//若有昵称和头像,就走你的昵称和头像;若没有,就走默认的
info.nickName = info.nickName ? info.nickName : '默认昵称'
info.avatar = info.avatar ? info.avatar : '/static/me/avatar.jpeg'
//将用户信息存储到vuex中
this.changeUserInfoActions(info)
} else {
this.$refs.uToast.show({
title: res.meta.msg,
type: 'warning',
icon: false
})
}
}).catch(err => {
console.log(err)
this.$refs.uToast.show({
title: err.meta.msg,
type: 'error',
icon: false
})
})
},
}
}
</script>
<style lang="scss">
@import "uview-ui/index.scss";
/*每个页面公共css */
@import "@/utils/iconfonts/iconfont.css";
@import "@/utils/font-awesome/css/font-awesome.css"
</style>
更多推荐
已为社区贡献5条内容
所有评论(0)