Vue实现pc端扫码+跳转h5登录
扫码功能和后端研究了好久,看了很多文章,不太符合我们的需求还好写出来了,就把逻辑整理了一下用的是微信扫码(公众号)需求是这样的:点击下图微信扫码,然后出现二维码,微信扫一扫跳转到h5页面,(如果微信没有绑定过就跳转绑定表单页面,填写表单成功后显示绑定成功,同时pc端登录成功,如果绑定过就跳转登录成功,同时pc端登录成功)第一步:申请一个服务号,注意不是订阅号,订阅号没有授权的功能。网上很多教怎么申
·
扫码功能和后端研究了好久,看了很多文章,不太符合我们的需求
还好写出来了,就把逻辑整理了一下
用的是微信扫码(公众号)
需求是这样的:点击下图微信扫码,然后出现二维码,微信扫一扫跳转到h5页面,(如果微信没有绑定过就跳转绑定表单页面,填写表单成功后显示绑定成功,同时pc端登录成功,如果绑定过就跳转登录成功,同时pc端登录成功)
第一步:
申请一个服务号,注意不是订阅号,订阅号没有授权的功能。网上很多教怎么申请的,这里就不说怎么申请的了
现在我们就拿到了appid还有域名
第二步:
点击微信的小图标,调用后端的接口得到uuid,同时开一个定时器检查uuid扫码状态,写到这里,前端的pc端逻辑就写完了(扫码确定后端会返回token)生成二维码
- 点击小图标获取uuid,前端拼接字符串 生成二维码
下载依赖 npm install qrcodejs2 --save
然后组件里引用 import QRCode from “qrcodejs2”; - 同时写一个定时器检查扫码状态,后端返回是过期的话显示二维码过期,点击刷新,同时清除定时器;后端返回已经登录状态就把传给前端的token放入缓存,同时路由跳转到主页,清除定时器
- 这里的token就是每次axios请求头里带着去访问后端接口的令牌,如果有疑问可以去看我之前权限管理动态路由的博客
下面是我的代码
js部分
<script>
import QRCode from "qrcodejs2";
export default {
data() {
return {
uuid: "",
timer: null,
baseUrl: process.env.VUE_APP_BASEURL,
needUpdate: false,
hasScan: false,
hasSuccess: false,
};
},
methods: {
//点击刷新
update() {
this.$refs.qrCodeContainer.innerHTML = "";
this.needUpdate = false;
this.getUuid();
this.timer = setInterval(() => {
this.checkUuid();
}, 1000);
},
//生成二维码
bindQRCode() {
new QRCode(this.$refs.qrCodeContainer, {
//这里很重要,在网上看了这里都是微信重定向的地址,我们的需求实现不了,其实是后端的地址!!!!!!给后端去判断重定向
//https://open.weixin.qq.com/connect/qrconnectappid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect 就是这一串,这里重定向的地址就是h5页面
text: this.baseUrl + "/acl/wx/wxScan/?uuid=" + this.uuid,
width: 140,
height: 140,
colorDark: "#333333", //二维码颜色
colorLight: "#ffffff", //二维码背景色
correctLevel: QRCode.CorrectLevel.L, //容错率,L/M/H
});
},
//得到uuid
getUuid() {
this.$api.getUUID().then((res) => {
if (res.success) {
this.uuid = res.data.uuid;
this.bindQRCode();
}
});
},
//检查uuid状态
checkUuid() {
this.$api.checkUUID({ UUID: this.uuid }).then((res) => {
if (res.data.ret === "3") {
clearInterval(this.timer);
this.hasSuccess = true;
this.$ls.set("token", res.data.token);
if (this.$ls.get("token")) {
//路由跳转
this.$router.push({ name: "main" });
}
} else if (res.data.ret === "2") {
clearInterval(this.timer);
this.needUpdate = true;
} else if (res.data.ret === "1") {
clearInterval(this.timer);
this.hasScan = true;
}
});
},
},
mounted() {
this.getUuid();
this.timer = setInterval(() => {
this.checkUuid();
}, 1000);
},
destroyed() {
clearInterval(this.timer);
},
//在页面离开时做的操作
beforeRouteLeave(to, from, next) {
this.$destroy();
next();
},
};
</script>
html部分
<h3>扫码登录</h3>
<div class="qrcode-container-total d-f a-c j-c">
<!--前端生成二维码,需要给二维码一个容器 -->
<div class="qrcode-container" ref="qrCodeContainer"></div>
<div class="qrcode-phone">
<img src="@/assets/img/scan-phone.png" alt="" />
</div>
</div>
<div class="dust d-f f-d a-c j-c" v-if="needUpdate">
<h4>二维码已失效</h4>
<a-button type="primary" @click="update"> 点击刷新 </a-button>
</div>
<div class="dust d-f f-d a-c j-c" v-if="hasScan">
<h4>已扫描</h4>
<h4>请在手机上确认登录</h4>
</div>
<div class="dust d-f f-d a-c j-c" v-if="hasSuccess">
<h4>登录成功,跳转中…</h4>
</div>
<p>请使用 微信扫一扫 扫描二维码登录</p>
<a class="ReturnLogin" @click="goLogin">返回登录</a>
</div>
第三步:
h5页面的逻辑,这里就没什么了,就是表单验证掉接口然后tab切换
唯一要注意的是要把uuid带着传给后端
<template>
<div>
<div class="container-bind-wechat" v-if="bindWechat">
<div class="title d-f j-c">
<p>绑定手机号</p>
</div>
<div class="logo d-f f-d a-c">
<div class="logo-box d-f j-c a-c">
<img src="@/assets/img/logo.png" alt="" />
</div>
<p>小牛后台管理系统</p>
</div>
<div class="ipt">
<a-input placeholder="请输入手机号" class="phone" v-model="phone" />
<a-input placeholder="请输入验证码" class="code" v-model="code" />
<div class="send-code">
<a-divider type="vertical" />
<a-button @click="sendVerifyCode" v-if="isSend">获取验证码</a-button>
<a-button v-if="!isSend" disabled>{{ count }}s</a-button>
</div>
<div class="tooltip d-f a-c j-c" v-if="visible">手机号格式错误~</div>
<div class="tooltip d-f a-c j-c" v-if="visibleToo">该手机号还没被注册过~</div>
<div class="tooltip d-f a-c j-c" v-if="visibleThird">请勾选复选框~</div>
<div class="tooltip d-f a-c j-c" v-if="visibleFifth">验证码格式错误~</div>
</div>
<div class="checkbox">
<a-checkbox :checked="checkAgree" @change="handleChange"> 同意 </a-checkbox>
<a class="login-service" href="" target="_blank"
>《服务协议》</a
>
<a class="login-policy" href="" target="_blank"
>《统一登录隐私政策》</a
>
</div>
<a-button type="primary" class="login-submit" @click="bindAndLogin">
绑定并登录
</a-button>
</div>
<div class="container-bind-success" v-if="bindSuccess">
<div class="title d-f j-c">
<p>绑定成功</p>
</div>
<div class="success d-f f-d a-c">
<div class="success-box d-f j-c a-c">
<img src="@/assets/img/bind-success.png" alt="" />
</div>
<p>恭喜您微信和手机号绑定成功</p>
<span>请使用微信扫码登录或手机号登录</span>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
phone: null,
code: null,
uuid: "",
checkAgree: true,
count: 30,
isSend: true,
timer: null,
visible: false,
visibleToo: false,
visibleThird: false,
visibleFifth: false,
bindWechat: true,
bindSuccess: false,
bindFailure: false,
};
},
methods: {
//复选框状态改变
handleChange(e) {
this.checkAgree = e.target.checked;
},
//发送验证码
sendVerifyCode() {
if (this.validatePhone(this.phone)) {
const TIME_COUNT = 60;
if (!this.timer) {
this.count = TIME_COUNT;
this.isSend = false;
//验证手机号已经注册过
this.$api.isExist({ phone: this.phone }).then((res) => {
// console.log(res)
if (res.success) {
//发送短信验证码
this.$api
.sendSmsCode({
phone: this.phone,
smsCodeType: 6,
})
.then((res) => {
// console.log(res)
return;
});
} else {
this.visibleToo = true;
this.phone = null;
setTimeout(() => {
this.visibleToo = false;
}, 3000);
}
});
this.timer = setInterval(() => {
if (this.count > 0 && this.count <= TIME_COUNT) {
this.count--;
} else {
this.isSend = true;
clearInterval(this.timer);
this.timer = null;
}
}, 1000);
}
}
},
validatePhone(value) {
let phone = /^[1][3,4,5,6,7,8,9][0-9]{9}$/;
if (!phone.test(value)) {
this.visible = true;
setTimeout(() => {
this.visible = false;
}, 3000);
return false;
} else {
return true;
}
},
validateCode(value) {
let code = /^[0-9]{4}$/;
if (!code.test(value)) {
this.visibleFifth = true;
setTimeout(() => {
this.visibleFifth = false;
}, 3000);
return false;
} else {
return true;
}
},
getUuid(url) {
let num = url.indexOf("?");
let str = url.substr(num + 1);
let arr = str.split("&");
let kv = [];
arr.forEach((r) => {
let n = r.indexOf("=");
let k = r.substring(0, n);
let v = r.substr(n + 1);
let obj = {};
obj[k] = v;
kv.push(obj);
});
return kv;
},
//绑定并登录
bindAndLogin() {
if (this.validatePhone(this.phone) && this.validateCode(this.code)) {
if (this.checkAgree) {
this.$api
.bindAndLogin({
phone: this.phone,
code: this.code,
uuid: this.uuid,
})
.then((res) => {
if (res.success) {
this.bindWechat = false;
this.bindSuccess = true;
} else {
this.bindWechat = false;
this.bindFailure = true;
}
});
} else {
this.visibleThird = true;
setTimeout(() => {
this.visibleThird = false;
}, 2000);
}
}
},
},
created() {
let url = location.href;
let arr = this.getUuid(url);
let obj = arr.find((r) => r.uuid);
if (obj != undefined) {
this.uuid = obj.uuid;
}
},
destroyed() {
clearInterval(this.timer);
},
//在页面离开时做的操作
beforeRouteLeave(to, from, next) {
this.$destroy();
next();
},
};
</script>
新手小白,写的不好,欢迎留言
更多推荐
已为社区贡献7条内容
所有评论(0)