山东大学项目实训(四)—— 微信小程序扫描web端二维码实现web端登录

效果

点击登录后,显示二维码→打开“探古”(本项目)微信小程序,扫描二维码确认登录→web端登录成功
二维码图片

主要流程

登录流程
因为本人主要负责web前端的开发,所以本文仅介绍web前端的实现方法

代码

生成随机值

我这里使用的是crypto.getRandomValues()方法,该方法可以获取符合密码学要求的安全的随机值,具体可参考:mdn web docs Crypto.getRandomValues()

二维码的生成使用的是qrcode.react包的QRCode组件,其value属性存储生成的随机值

    // 获得随机的qr值
    function getQRvalue() {
    
    
        const array = new Uint32Array(1);
        // Crypto.getRandomValues() 方法让你可以获取符合密码学要求的安全的随机值
        window.crypto.getRandomValues(array);
        let random = array[0].toString();
        setQrvalue(random)
        console.log(random)
        return random;
    }

实现带倒计时的轮询

这一部分需要非常注意setInterval的闭包属性!

1. 实现二维码展示的倒计时

        // qrCountdown为展现在页面上的剩余时间
        let t = qrCountdown;
        let qrTimer = setInterval(() => {
    
    
            console.log("in qrtimer:", t)
            t--;
            setQrCountdown(t)
            // 到时间
            if (t < 0) {
    
    
                // qrTimer是二维码倒计时计时器
                clearInterval(qrTimer)
                // timerInter是定义在全局的轮询计时器
                clearInterval(timerInter)
                setLoginModalVisible(false)
                // 重置展现在页面上的剩余时间
                setQrCountdown(60)
            }
        }, 1000)
        // 设置qrTimer为一个状态
        setQrTimer(qrTimer);

注意这里setInterval第一个参数方法内部不能直接使用qrCountdown去作为上一个值来减!因为它会产生一个闭包,记住qrCountdown的值,所以实际上每次调用,qrCountdown都是原来的值,不会因为setQrCountdown而发生变化,会造成错误

2. 实现轮询计时器

2.1 参数列表

function getLoginInfo(rand, stop, qrTimer) {
    
    }

传入参数:

  1. 二维码带的rand值
  2. 是否不重复倒计时
    主要是判断是否是第一次调用该方法,如果是第一次调用,则设置计时器;否则跳过。
  3. 二维码倒计时器
    为什么需要把这个传入呢?因为在进行setInterval时,内部会产生一个闭包,在内部设置清除计时器清除的是一开始进入getLoginInfo方法时的计时器,即初始计时器编号(我设置的是0),而不是后面经过setInterval赋值以后的计时器编号。因为它内部产生了一个闭包,即使外部的计时器编号已经发生了改变,但是它内部依然不会变!
    所以我这里在二维码计时器已经定义好了以后,即上一部分实现二维码展示的倒计时的代码后面,调用该方法,将已定义好的二维码倒计时计时器qrTime传入该方法中

2.2 具体实现

    let timerInter;
    function getLoginInfo(rand, stop, qrTimer) {
    
    
        console.log("polling")
        console.log("getLoginInfo timerInter:", timerInter)
        axios({
    
    
            method: 'post',
            url: '/api/user/getLoginInfo',
            // 传入二维码的rand
            data: qs.stringify({
    
    
                rand
            })
        })
            .then((res) => {
    
    
                // 如果轮询成功
                if (res.data.success) {
    
    
                    console.log(res.data.data)
                    // 设置用户参数
                    setUserInfo(res.data.data)
                    // 清除当前的轮询计时器
                    clearInterval(timerInter)
                    // 清除二维码倒计时计时器
                    clearInterval(qrTimer)
                    setHasLogined(true)
                    setLoginModalVisible(false)
                    setQrCountdown(60)
                    Modal.success({
    
    
                        content: "登录成功!"
                    })
                } else {
    
    
                    // 轮询未获得
                    console.log(res.data.message)
                    // stop表示是否是第一次轮询
                    // !stop为true表示是第一次调用该函数,则设置计时器
                    if (!stop) {
    
    
                        // 每隔4秒调用一次该方法
                        // 并将第二个参数改为true,表示后面不需要再设置计时器
                        // 并将二维码倒计时计时器传入
                        timerInter = setInterval(() => getLoginInfo(rand, true, qrTimer), 4000)
                        // 记录轮询计时器的编号,方便在外部对该计时器进行清除
                        setTimer(timerInter)
                    }
                }
            })
            .catch((error) => console.log(error))
    }

这里设置了一个轮询计时器编号的状态time,并通过setTimer()把当前计时器的编号记录下来了。因此,如果用户点击主动关闭二维码框,也就是调用Modal的onCancel()方法(这个方法在闭包外面),也可以去清除轮询计时器,中止轮询。

猜你喜欢

转载自blog.csdn.net/weixin_45830447/article/details/125144421