持久登录+手机验证码注册系统.png
    持久登录+手机验证码注册系统2.png

    1. <!DOCTYPE html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>登录注册模块</title>
    6. <link rel="stylesheet" href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css">
    7. <link rel="stylesheet" href="css/index.css" />
    8. </head>
    9. <body>
    10. <div class="modal-container js_modal">
    11. <div class="mod-box login-box">
    12. <a href="javascript:;" class="fa fa-times js_closeBtn"></a>
    13. <div class="hd">
    14. <h1>用户登录</h1>
    15. </div>
    16. <div class="bd">
    17. <div class="error-tip js_errorTip"></div>
    18. <form action="http://localhost/api_for_study2/index.php/User/login" method="post" id="js_loginForm">
    19. <div class="input-box">
    20. <label for="js_username" class="fa fa-user"></label>
    21. <input type="text" id="js_username" class="text-input" placeholder="用户名|手机号" maxlength="20" />
    22. </div>
    23. <div class="input-box">
    24. <label for="js_password" class="fa fa-lock"></label>
    25. <input type="password" id="js_password" class="text-input" placeholder="密码" maxlength="20" />
    26. </div>
    27. <div class="input-box">
    28. <input type="checkbox" id="js_persistedLogin" />
    29. <label for="js_persistedLogin" class="checkbox-label">保持登录30天</label>
    30. </div>
    31. <div class="input-box">
    32. <button type="submit" class="login-btn js_loginBtn">登录</button>
    33. </div>
    34. </form>
    35. </div>
    36. </div>
    37. <div class="mod-box reg-box">
    38. <a href="javascript:;" class="fa fa-times js_closeBtn"></a>
    39. <div class="hd">
    40. <h1>用户注册</h1>
    41. </div>
    42. <div class="bd">
    43. <div class="error-tip js_errorTip"></div>
    44. <form action="http://localhost/api_for_study/index.php/User/register" method="post" id="js_regForm">
    45. <div class="input-box">
    46. <label for="js_rnumber" class="fa fa-user"></label>
    47. <input type="text" id="js_rnumber" class="text-input" placeholder="手机号 11位" maxlength="11" />
    48. </div>
    49. <div class="input-box">
    50. <label for="js_password" class="fa fa-lock"></label>
    51. <input type="password" id="js_rpassword" class="text-input" placeholder="密码 6-20位" maxlength="20" />
    52. </div>
    53. <div class="input-box">
    54. <label for="js_rtelcode" class="fa fa-mobile-phone"></label>
    55. <input type="text" id="js_rtelcode" class="text-input" placeholder="手机验证码 6位" maxlength="6" />
    56. <button class="input-btn js_sendCodeBtn" value="http://localhost/api_for_study/index.php/User/sendTelCode">发送验证码</button>
    57. </div>
    58. <div class="input-box">
    59. <label for="js_rpasscode" class="fa fa-unlock"></label>
    60. <input type="text" id="js_rpasscode" class="text-input" placeholder="验证码 4位" maxlength="4" />
    61. <img src="http://localhost/api_for_study/index.php/User/verify" class="code-img js_codeImg" alt="刷新验证码" title="刷新验证码" />
    62. </div>
    63. <div class="input-box">
    64. <button type="submit" class="login-btn js_regBtn">注册</button>
    65. </div>
    66. </form>
    67. </div>
    68. </div>
    69. </div>
    70. <header class="header">
    71. <div class="user">
    72. <div class="user-item js_loginStatus">
    73. <a href="javascript:;" class="user-btn js_openLoginBtn">登录</a>
    74. <a href="javascript:;" class="user-btn js_openRegBtn">注册</a>
    75. </div>
    76. </div>
    77. </header>
    78. <script type="text/html" id="js_loginTpl">
    79. <a href="javascript:;" class="user-btn js_openLoginBtn">登录</a>
    80. <a href="javascript:;" class="user-btn js_openRegBtn">注册</a>
    81. </script>
    82. <script type="text/html" id="js_userTpl">
    83. <span class="nickname">欢迎您,{{nickname}}</span>
    84. <a href="http://localhost/api_for_study2/index.php/User/logout" class="user-btn js_logout">退出</a>
    85. </script>
    86. <script src="js/utils.js"></script>
    87. <script src="js/users.js"></script>
    88. <script src="js/index.js"></script>
    89. <script type="text/javascript">
    90. main.init();
    91. </script>
    92. </body>
    93. </html>
    body{
        margin: 0;
    }
    
    a{
        text-decoration: none;
        color: #333;
    }
    
    h1{
        font-weight: normal;
        margin: 0;
    }
    
    div{
        box-sizing: border-box;
    }
    
    input,
    button{
        outline: none;
        border: none;
    }
    
    .header{
        width: 100%;
        height: 60px;
        background-color: #424242;
    }
    
    .header .user{
        float: right;
        height: 100%;
    }
    
    .header .user-item{
        float: left;
        height: 100%;
        padding: 0 20px;
        text-align: center;
        line-height: 60px;
    }
    
    .header .user-item .nickname{
        color: #fff;
        margin-right: 15px;
    }
    
    .header .user-item .user-btn{
        margin-left: 20px;
        color: #ccc;
    }
    
    .header .user-item .user-btn:hover{
        color: #fff;
    }
    
    .modal-container{
        display: none;
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background-color: rgba(0, 0, 0, .6);
    }
    
    .modal-container.show{
        display: block;
    }
    
    .modal-container .fa-times{
        position: absolute;
        right: 15px;
        top: 16px;
        font-size: 18px;
        color: #fff;
    }
    
    .modal-container .mod-box{
        display: none;
        position: absolute;
        left: 50%;
        top: 50%;
        margin: -175px 0 0 -200px;
        width: 400px;
        background-color: #fff;
        border-radius: 10px;
        box-shadow: 1px 3px 5px #333;
        overflow: hidden;
    }
    
    .modal-container.show.login .login-box{
        display: block;
    }
    
    .modal-container.show.reg .reg-box{
        display: block;
    }
    
    .modal-container .mod-box .error-tip{
        height: 30px;
        color: red;
        font-size: 14px;
    }
    
    .modal-container .mod-box .hd{
        height: 50px;
        background-color: #57B7F9;
        text-align: center;
        line-height: 50px;
    
    }
    
    .modal-container .mod-box .hd h1{
        font-size: 18px;
        color: #fff;
    }
    
    .modal-container .mod-box .bd{
        padding: 30px 30px 15px 30px;
    }
    
    .modal-container .mod-box .bd .input-box{
        position: relative;
        height: 35px;
        margin-bottom: 20px;
    }
    
    .modal-container .mod-box .bd .input-box input{
        width: 100%;
        height: 100%;
        text-indent: 30px;
        font-size: 16px;
        border: 1px solid #ddd;
    }
    
    .modal-container .mod-box .bd .input-box .text-input:focus{
        border-color: #57B7F9;
        box-shadow: 0 0 2px #57B7F9;
    }
    
    .modal-container .mod-box .bd .input-box label{
        position: absolute;
        top: 11px;
        left: 10px;
        font-size: 18px;
    }
    
    .modal-container .mod-box .bd .input-box input[type="checkbox"]{
        margin-top: -2px;
    }
    
    .modal-container .mod-box .bd .input-box .checkbox-label{
        font-size: 14px;
        left: 30px;
        top: 6px;
        color: #666;
    }
    
    .modal-container .mod-box .bd .input-box .login-btn{
        width: 100%;
        height: 100%;
        background-color: #57B7F9;
        color: #fff;
        font-size: 16px;
    }
    
    .modal-container .mod-box .bd .input-box .input-btn{
        position: absolute;
        top: 4px;
        right: 4px;
        height: 30px;
        border: 1px solid #ddd;
        cursor: pointer;
    }
    
    .modal-container .mod-box .bd .input-box .input-btn.disabled{
        background-color: #ededed;
        color: #999;
    }
    
    .modal-container .mod-box .bd .input-box .code-img{
        position: absolute;
        top: 4px;
        right: 4px;
        height: 30px;
        border: 1px solid #ddd;
        cursor: pointer;
    }
    

    index.js

    var main = (function (doc, loginAction, regAction) {
        var oOpenLoginBtn = doc.getElementsByClassName('js_openLoginBtn')[0],
            oOpenRegBtn = doc.getElementsByClassName('js_openRegBtn')[0],
            oCloseLoginBtn = doc.getElementsByClassName('js_closeBtn')[0],
            oCloseRegBtn = doc.getElementsByClassName('js_closeBtn')[1],
            oErrorTip = doc.getElementsByClassName('js_errorTip')[0],
            oLoginBtn = doc.getElementsByClassName('js_loginBtn')[0],
            oRegBtn = doc.getElementsByClassName('js_regBtn')[0],
            oSendCodeBtn = doc.getElementsByClassName('js_sendCodeBtn')[0],
            // 登录用户名
            oLoginStatus = doc.getElementsByClassName('js_loginStatus')[0],
            oCodeImg = doc.getElementsByClassName('js_codeImg')[0],
    
    
            loginTpl = doc.getElementById('js_loginTpl').innerHTML,
            userTpl = doc.getElementById('js_userTpl').innerHTML;
    
        //方法私有化
    
        // 绑定函数
        function bindEvent() {
            // 登录对话框打开与关闭
            oOpenLoginBtn.addEventListener('click', loginAction.openLoginBoard.bind(null, true), false);
            oCloseLoginBtn.addEventListener('click', loginAction.openLoginBoard.bind(null, false), false);
            // 注册对话框打开与关闭
            oOpenRegBtn.addEventListener('click', regAction.openRegBoard.bind(null, true), false);
            oCloseRegBtn.addEventListener('click', regAction.openRegBoard.bind(null, false), false);
            // 登录功能
            oLoginBtn.addEventListener('click', loginAction.login.bind(loginAction), false);
            // 点击发送手机验证码
            oSendCodeBtn.addEventListener('click', regAction.sendTelCode.bind(regAction, oSendCodeBtn), false);
            // 点击更新图片验证码 
            oCodeImg.addEventListener('click', regAction.refreshCode.bind(null, oCodeImg), false);
            // 注册功能
            oRegBtn.addEventListener('click', regAction.register.bind(regAction), false);
        }
    
        // 渲染用户名功能
        function renderUserArea(isLogin) {
            if (isLogin) {
                manageCookies.get('nickname', function (cookie) {
                    // 模板渲染
                    oLoginStatus.innerHTML = userTpl.replace(/{{(.*?)}}/g, cookie);
                });
            } else {
                oLoginStatus.innerHTML = loginTpl;
            }
        }
    
        return {
            // 初始化功能
            init: function () {
                this.checkAuth();
                bindEvent();
            },
            // 验证cookie有效期
            checkAuth: function () {
    
                // 获取manageCookies方法
                manageCookies.get('auth', function (cookie) {
                    if (cookie != undefined) {
                        xhr.ajax({
                            url: 'http://localhost/api_for_study/index.php/User/checkAuth',
                            type: 'POST',
                            dataType: 'JSON',
                            data: {
                                auth: cookie
                            },
                            success: function (data) {
                                var code = data.error_code,
                                    errorInfo = '';
    
                                switch (code) {
                                    case '1006':
                                        errorInfo = '登录验证不通过,请重试';
                                        loginAction.openLoginBoard(true);
                                        renderUserArea(false);
                                        break;
                                    case '1007':
                                        errorInfo = '登录已过期,请重试';
                                        loginAction.openLoginBoard(true);
                                        renderUserArea(false);
                                        break;
                                    case '200':
                                        renderUserArea(true);
                                        break;
                                    default:
                                        break;
                                }
                                oErrorTip.innerHTML = errorInfo;
                            }
                        });
                    }
                });
            }
        }
    
    
    })(document, loginAction, regAction);
    

    user.js

    // 登录模块
    var loginAction = (function (doc) {
        var oModal = doc.getElementsByClassName('js_modal')[0],
            submitURL = doc.getElementById('js_loginForm').action,
            oUsername = doc.getElementById('js_username'),
            oPassword = doc.getElementById('js_password'),
            oErrorTip = doc.getElementsByClassName('js_errorTip')[0],
            // 登录状态保存时间
            oPersistedLogin = doc.getElementById('js_persistedLogin');
    
        // 提交用户名/密码/登录持续时间
        function _submitForm(data) {
            xhr.ajax({
                url: submitURL,
                type: 'POST',
                data: data,
                success: function (data) {
                    var code = data.error_code,
                        errorInfo = '';
                    switch (code) {
                        case '1001':
                            errorInfo = '用户名长度不正确';
                            break;
                        case '1002':
                            errorInfo = '密码长度不正确';
                            break;
                        case '1003':
                            errorInfo = '此用户名不存在';
                            break;
                        case '1004':
                            errorInfo = '密码不正确';
                            break;
                        case '1005':
                            errorInfo = '登录失败,请重试';
                            break;
                        case '200':
                            // 刷新页面
                            location.reload();
                            break;
                        default:
                            break;
                    }
                    oErrorTip.innerHTML = errorInfo;
                }
            });
        }
    
        return {
            // 打开关闭窗口
            openLoginBoard: function (show) {
                if (show) {
                    oModal.className += ' show login';
                    console.log(oModal);
                } else {
                    oModal.className = 'modal-container js-modal';
                }
                console.log('123');
            },
            // 登录前的数据验证
            login: function (e) {
                var e = e || window.event;
                e.preventDefault();
                console.log(oUsername.value, oPassword.value);
                var username = trimSpace(oUsername.value),
                    password = trimSpace(oPassword.value);
                if (username.length < 6 || username.length > 20) {
                    oErrorTip.innerText = '用户名长度:6-20位';
                    return;
                }
                if (password.length < 6 || password.length > 20) {
                    oErrorTip.innerText = '密码名长度:6-20位';
                    return;
                }
                oErrorTip.innerHTML = '';
                _submitForm({
                    username: username,
                    password: password,
                    isPersistedLogin: oPersistedLogin.checked
                })
            }
        }
    })(document);
    
    // 注册模块
    var regAction = (function (doc) {
        var oModal = doc.getElementsByClassName('js_modal')[0],
            submitURL = doc.getElementById('js_regForm').action,
            sendTelCodeURL = doc.getElementsByClassName('js_sendCodeBtn')[0].value,
            oNumber = doc.getElementById('js_rnumber'),
            oPassword = doc.getElementById('js_rpassword'),
            oTelCode = doc.getElementById('js_rtelcode'),
            oPassCode = doc.getElementById('js_rpasscode'),
            oErrorTip = doc.getElementsByClassName('js_errorTip')[1],
            oCodeImg = doc.getElementsByClassName('js_codeImg')[0],
    
            // 手机验证码 默认没发送
            telCodeBtnDisabled = false;
    
        var t = null,
            s = 60,
            os = 60;
    
        // 提交注册
        function _submitForm(data, that) {
    
            xhr.ajax({
                url: submitURL,
                type: 'POST',
                dataType: 'JSON',
                data: data,
                success: function (data) {
                    var code = data.error_code,
                        errorInfo = '';
    
                    switch (code) {
                        case '1008':
                            errorInfo = '手机号格式不正确';
                            break;
                        case '1002':
                            errorInfo = '密码长度:6-20位';
                            break;
                        case '1009':
                            errorInfo = '图片验证码不正确';
                            break;
                        case '1010':
                            errorInfo = '与接收验证码的手机号不一致';
                            break;
                        case '1011':
                            errorInfo = '短信验证码不正确';
                            break;
                        case '1014':
                            errorInfo = '注册失败,请重试';
                        default:
                            break;
                    }
                    oErrorTip.innerText = errorInfo;
                    // 每次提交表单都刷新图片验证码
    
                    // 因为refreshCode方法不是此对象的所以要把this传过来
                    that.refreshCode(oCodeImg);
                    if (code == '200') {
                        oErrorTip.innerText = '注册成功';
                        setTimeout(function () {
                            location.reload();
                        }, 300);
                    }
                }
            });
        }
    
        // 发送验证码按钮状态变化
        function countDown(obj) {
            console.log(obj);
            if (s <= 0) {
                // console.log(s);
                clearInterval(t);
                t = null;
                s = os;
                obj.className = 'input-btn js_sendCodeBtn';
                // 变成可点击状态
                obj.disabled = false;
                obj.innerText = '获取验证码';
                telCodeBtnDisabled = false;
            } else {
                s--;
                //更改不可点击的状态对应的颜色
                obj.className += 'disabled';
                //将按钮设置为不可点击
                obj.disabled = true;
                obj.innerText = '已发送' + s + '秒';
                telCodeBtnDisabled = true;
            }
        }
    
        return {
            // 打开/关闭 注册窗口
            openRegBoard: function (show) {
                if (show) {
                    oModal.className += ' show reg';
                } else {
                    oModal.className = 'modal-container js-modal';
                }
            },
    
            // 发送验证手机验证码
            sendTelCode: function (btn) {
                var event = arguments[1],
                 e = event || window.event;
                //  console.log(e);
                e.preventDefault();
    
                var pNumber = trimSpace(oNumber.value);
    
                if (pNumber.length !== 11) {
                    oErrorTip.innerText = '手机号长度:11位';
                    return;
                }
                if (!phoneNumberCheck(pNumber)) {
                    oErrorTip.innerText = '手机号格式不正确';
                    return;
                }
    
                if (!telCodeBtnDisabled) {
                    btn.innerHTML = '<i class="fa fa-spinner fa-spin"></i>';
                    xhr.ajax({
                        url: sendTelCodeURL,
                        type: 'POST',
                        dataType: 'JSON',
                        data: {
                            pNumber: pNumber
                        },
                        success: function (data) {
                            var code = data.error_code,
                                errorInfo = '';
                            switch (code) {
                                case '1008':
                                    // 手机号不正确就不让发送验证码
                                    errorInfo = '手机号格式不正确';
                                    btn.innerText = '获取验证码';
                                    break;
                                case '1012':
                                    errorInfo = '手机号已被使用';
                                    btn.innerText = '获取验证码';
                                    break;
                                case '1013':
                                    errorInfo = '验证码发送失败';
                                    btn.innerText = '获取验证码';
                                case '200':
                                    // 延迟一秒执行倒计时发送验证码倒计时
                                    t = setInterval(countDown.bind(null, btn), 1000);
                                    errorInfo = '验证码发送成功';
                                    break;
                                default:
                                    errorInfo = '验证码发送失败';
                                    btn.innerText = '获取验证码';
                                    break;
                            }
                            oErrorTip.innerText = errorInfo;
    
                        }
                    });
                }
            },
    
            // 更新图片验证码
            refreshCode: function (obj) {
                var imgUrl = obj.src;
    
                // 更新验证码图片
                obj.src = imgUrl.indexOf('?') > 0 ?
                    imgUrl.replace(/\?.*$/, '') + '?rand=' + Math.random() :
                    imgUrl + '?rand=' + Math.random();
    
            },
    
            // 注册前验证数据格式
            register: function (e) {
                console.log(e);
                var e = e || window.event;
                e.preventDefault();
    
                var pNumber = trimSpace(oNumber.value),
                    password = trimSpace(oPassword.value),
                    // 手机验证码
                    telcode = trimSpace(oTelCode.value),
                    // 图片验证码
                    passcode = trimSpace(oPassCode.value);
                if (pNumber.length !== 11) {
                    oErrorTip.innerText = '手机号长度:11位';
                    return;
                }
                if (!phoneNumberCheck(pNumber)) {
                    oErrorTip.innerText = '手机格式不正确'
                    return;
                }
                if (password.length < 6 || password.length > 20) {
                    oErrorTip.innerText = '密码长度:6-20位';
                    return;
                }
    
                if (telcode.length !== 6) {
                    oErrorTip.innerText = '手机验证码长度:6位';
                    return;
                }
    
                // 验证是否是数字
                if (digitCheck(telcode)) {
                    oErrorTip.innerText = '手机验证码必须是数字';
                    return;
                }
    
                if (passcode.length !== 4) {
                    oErrorTip.innerText = '图片验证码长度:4位';
                    return;
                }
    
                if (alphabetCheck(passcode)) {
                    oErrorTip.innerText = '图片验证码必须是字母';
                    return;
                }
                oErrorTip.innerHTML = '';
                _submitForm({
                    pNumber: pNumber,
                    password: password,
                    telcode: telcode,
                    passcode: passcode
                },this);
            }
        }
    })(document);