美文网首页我爱编程
angularjs登录注册表单实践

angularjs登录注册表单实践

作者: defphot | 来源:发表于2018-03-18 19:03 被阅读0次

    使用AngularJS实现登录与注册

    html和css布局

    我们采用html+css框架bootstrap4,里面有很多已定义好的组件,可以拿过来直接用,非常简单,对于实现我们想要的功能,效率非常高。点击查看boststrap4官方文档

    我想把登录界面和注册界面集成在同一个页面上,于是想起了bs中的navs组件,利用该组件就可以切换不同的表单。

    <nav>
        <div class="nav nav-tabs" id="nav-tab" role="tablist">
            <a class="nav-item nav-link w-50 text-center active"
               id="nav-login-tab"
               href="#nav-login"
               role="tab"
               data-toggle="tab"
               aria-controls="nav-login"
               aria-selected="true">
               <strong>Login</strong>
            </a>
            <a class="nav-item nav-link w-50 text-center"
               id="nav-register-tab"
               href="#nav-register"
               role="tab"
               data-toggle="tab"
               aria-controls="nav-register"
               aria-selected="false">
               <strong>Register</strong>
            </a>
        </div>
    </nav>
    

    通过引入jQuery,bs4可以自动帮你完成界面的切换,点击<a>链接实际指向以下内容:

    <div class="tab-content mt-4" id="nav-tabContent">
        <div class="tab-pane fade show active" id="nav-login" role="tabpanel" aria-labelledby="nav-login-tab">
            ......
        </div>
        <div class="tab-pane fade" id="nav-register" role="tabpanel" aria-labelledby="nav-register-tab">
            ...... 
        </div>
    </div>
    

    通过在tab-pane中放置form表单就可以达到登录界面和注册界面的切换,以下是登录界面的form代码:

    <form novalidate="novalidate" name="loginForm">
        <div class="form-group">
            <label for="lemail">Account</label>
            <input type="email"
                   class="form-control my-input"
                   id="lemail"
                   placeholder="Enter your account"
                   name="lemail"
                   required="required"
                   ng-minlength="6"
                   ng-maxlength="18"
                   ng-model="login_user.email"
                   email-check-login>
    
            <div ng-cloak ng-if="loginForm.lemail.$dirty&&loginForm.lemail.$invalid">
                <span class="error" ng-if="loginForm.lemail.$error.required">
                    Your account is required.
                </span>
                <span class="error" ng-if="!loginForm.lemail.$error.minlength&&!loginForm.lemail.$error.maxlength&&loginForm.lemail.$error.email">
                    It is not a valid account.
                </span>
                <span class="error" ng-if="loginForm.lemail.$error.minlength">
                    Your account is required to be at least 6 characters.
                </span>
                <span class="error" ng-if="loginForm.lemail.$error.maxlength">
                    Your account cannot be longer than 18 characters.
                </span>
                <span class="error" ng-if="!loginForm.lemail.$error.email&&loginForm.lemail.$error.email_error">
                    Your account does not exist.
                </span>
            </div>
        </div>
        <div class="form-group">
            <label for="lpassword">Password</label>
            <input type="password"
                   class="form-control my-input"
                   id="lpassword"
                   placeholder="Enter your password"
                   name="lpassword"
                   required="required"
                   ng-minlength="6"
                   ng-maxlength="18"
                   ng-model="login_user.password">
    
            <div ng-cloak ng-if="loginForm.lpassword.$dirty&&loginForm.lpassword.$invalid">
                <span class="error" ng-if="loginForm.lpassword.$error.required">
                    Your password is required.
                </span>
                <span class="error" ng-if="!loginForm.lpassword.$error.minlength&&!loginForm.lpassword.$error.maxlength&&loginForm.lpassword.$error.password">
                    It is not a valid password.
                </span>
                <span class="error" ng-if="loginForm.lpassword.$error.minlength">
                    Your password is required to be at least 6 characters.
                </span>
                <span class="error" ng-if="loginForm.lpassword.$error.maxlength">
                    Your password cannot be longer than 18 characters.
                </span>
            </div>
        </div>
        <div class="form-check">
            <input type="checkbox" class="form-check-input" id="remember-me" ng-model="login_user.remember_me">
            <label class="form-check-label" for="remember-me">Remember me, <em>validity will last for one week.</em></label>
        </div>
        <button type="submit" class="mt-15 btn btn-primary btn-block" ng-disabled="loginForm.$invalid">Login</button>
    </form>
    

    登录界面长这个样子:

    登录界面.png

    以下是注册页面代码:

    <form novalidate="novalidate" name="registerForm">
        <div class="form-group">
            <label for="remail">Create Account</label>
            <input type="email"
                   class="form-control my-input"
                   id="remail"
                   placeholder="Create your account"
                   name="remail"
                   required="required"
                   ng-minlength="6"
                   ng-maxlength="18"
                   ng-model="register_user.email"
                   email-check>
    
            <div ng-cloak ng-if="registerForm.remail.$dirty&&registerForm.remail.$invalid">
                <span class="error" ng-if="registerForm.remail.$error.required">
                    Your account is required.
                </span>
                <span class="error" ng-if="!registerForm.remail.$error.minlength&&!registerForm.remail.$error.maxlength&&registerForm.remail.$error.email">
                    It is not a valid account.
                </span>
                <span class="error" ng-if="registerForm.remail.$error.minlength">
                    Your account is required to be at least 6 characters.
                </span>
                <span class="error" ng-if="registerForm.remail.$error.maxlength">
                    Your account cannot be longer than 18 characters.
                </span>
                <!--ensure unique need back-end support-->
                <span class="error" ng-if="!registerForm.remail.$error.email&&registerForm.remail.$error.email_error">
                    Your account is taken, please try another one.
                </span>
            </div>
        </div>
        <div class="form-group">
            <label for="rpassword">Create Password</label>
            <input type="password"
                   class="form-control my-input"
                   id="rpassword"
                   placeholder="Create your password"
                   name="rpassword"
                   required="required"
                   ng-minlength="6"
                   ng-maxlength="18"
                   ng-model="register_user.password"
                   password-check>
    
            <div ng-cloak ng-if="registerForm.remail.$valid&&registerForm.rpassword.$dirty&&registerForm.rpassword.$invalid">
                <span class="error" ng-if="registerForm.rpassword.$error.required">
                    Your password is required.
                </span>
                <span class="error" ng-if="!registerForm.rpassword.$error.minlength&&!registerForm.rpassword.$error.maxlength&&registerForm.rpassword.$error.email">
                    It is not a valid password.
                </span>
                <span class="error" ng-if="registerForm.rpassword.$error.minlength">
                    Your password is required to be at least 6 characters.
                </span>
                <span class="error" ng-if="registerForm.rpassword.$error.maxlength">
                    Your password cannot be longer than 18 characters.
                </span>
                <!--ensure strength need back-end support-->
                <span class="error" ng-if="!registerForm.rpassword.$error.email&&registerForm.rpassword.$error.password_error">
                    Your password is so weak, please try another one stronger.
                </span>
            </div>
        </div>
        <div class="form-group">
            <label for="cpassword">Confirm Password</label>
            <input type="password"
                   class="form-control my-input"
                   id="cpassword"
                   placeholder="Confirm your password"
                   name="cpassword"
                   required="required"
                   ng-model="register_user.confirm_password"
                   equal-check="register_user.password">
    
            <div ng-cloak ng-if="registerForm.rpassword.$valid&&registerForm.cpassword.$dirty&&registerForm.cpassword.$invalid">
                <span class="error" ng-if="registerForm.cpassword.$error.required">
                    Confirm password is required.
                </span>
                <!--confirm password-->
                <span class="error" ng-if="!registerForm.cpassword.$error.required&&registerForm.cpassword.$error.not_equal">
                    The confirm password entered is invalid.
                </span>
            </div>
        </div>
        <div class="form-check">
            <input type="checkbox"
                   class="form-check-input"
                   id="accept"
                   name="accept"
                   ng-model="register_user.accept"
                   accept-check>
    
            <label class="form-check-label" for="accept"><em>I have read all the <a href="#" class="blue" data-toggle="modal" data-target="#acceptTerms">agreements</a>.</em></label>
            <div ng-if="registerForm.rpassword.$valid&&registerForm.cpassword.$valid&&registerForm.accept.$dirty&&registerForm.accept.$invalid">
                <span class="error" ng-if="registerForm.accept.$error.not_checked">
                    You must agree with all the terms.
                </span>
            </div>
        </div>
        <button type="submit" class="mt-15 btn btn-primary btn-block" ng-disabled="registerForm.$invalid">Register</button>
    </form>
    

    注册界面长这个样子:

    注册页面.png

    javacript代码和angularjs代码

    弹出效果

    由于加载的原因,所有错误信息总是会在加载的时候先出现,再马上消失,很难看,所以写了一个js代码避免这个效果:

    思路就是先把整个容器的透明度设置为0,加载之后再把透明度调至1,在透明的这段时间内,错误信息无法察觉,代码:

    function getStyle(obj,name) {
        if(obj.currentStyle){
            return obj.currentStyle[name];
        }
        else{
            return getComputedStyle(obj,null)[name];
        }
    }
    
    function startMove(obj,json,ispeed,fnEnd) {
        clearInterval(obj.timer);
        obj.timer = setInterval(function () {
            var bStop = true;
    
            for(var attr in json){
                var cur = 0;
                if(attr =='opacity'){
                    cur = Math.round(parseFloat(getStyle(obj,attr))*100);
                }
                else{
                    cur = parseInt(getStyle(obj,attr));
                }
                var speed = (json[attr]-cur)/ispeed;
                speed = speed>0?Math.ceil(speed):Math.floor(speed);
    
                if(cur!=json[attr]){
                    bStop = false;
                }
    
                if(attr == 'opacity'){
                    obj.style.filter='alpha(opacity:'+(cur+speed)+')';
                    obj.style.opacity=(cur+speed)/100;
                }
                else{
                    obj.style[attr]=cur+speed+'px';
                }
            }
            if(bStop){
                clearInterval(obj.timer);
                if(fnEnd){
                    fnEnd();
                }
            }
        },30)
    }
    
    window.onload = function () {
        var mainForm = document.getElementById('mainForm');
        startMove(mainForm,{'opacity':100},6);
    };
    

    验证表单

    使用angularjs自带的表单状态验证器

    ng-valid is set if the form is valid.
    ng-invalid is set if the form is invalid.
    ng-pending is set if the form is pending.
    ng-pristine is set if the form is pristine.
    ng-dirty is set if the form is dirty.
    ng-submitted is set if the form was submitted.
    

    以及输入字段校验指令,具体使用方法官方文档

    剩下我们需要自己写的指令有:

    1、确认密码和输入密码的相等性判断
    2、接受所有条款,否则无法继续注册
    3、异步请求服务器,判断账号是否已存在
    4、异步请求服务器,判断密码格式和强度要求

    1、首先相等判断:

    app.directive('equalCheck',function(){
        return{
            require : 'ngModel',
            scope : {
                orgText : '=equalCheck'
            },
            link : function(scope, elm, attrs, ctrl){
                ctrl.$validators.not_equal = function(viewValue) {
                    return viewValue === scope.orgText;
                };
                scope.$watch('orgText', function() {
                    ctrl.$validate();
                });
            }
        }
    });
    

    html上这样绑定

    <input ... ng-model="register_user.confirm_password" equal-check="register_user.password">
    

    使用not_equal判断错误信息是否显示:

    <span class="error" ng-if="...registerForm.cpassword.$error.not_equal">The confirm password entered is invalid.</span>
    

    2、必须接受条款判断:

    app.directive('acceptCheck', function() {
        return {
            require : 'ngModel',
            link : function(scope, elm, attrs, ctrl) {
                ctrl.$parsers.push(function(viewValue) {
                    if (viewValue === true) {
                        ctrl.$setValidity('not_checked', true);
                    } else {
                        ctrl.$setValidity('not_checked', false);
                    }
                    return viewValue;
                });
            }
        };
    });
    

    html上这样绑定:

    <input ... ng-model="register_user.accept" accept-check>
    

    使用not_checked判断错误信息是否显示:

    <span class="error" ng-if="registerForm.accept.$error.not_checked">You must agree with all the terms.</span>
    

    为了使接受条款默认选中,我们可以在控制器中设置:

    $scope.login_user = {};
    $scope.register_user = {};
    $scope.register_user.accept = true;
    

    3、4、异步请求服务器,提交密码账号,接受返回结果,显示错误信息指令代码:

    app.directive('emailCheck',function ($http, $log, $rootScope) {
        var timer;
        return{
            require : 'ngModel',
            link : function(scope, elm, attrs, ctrl) {
                elm.bind('keyup', function() {
                    if(!(scope.registerForm.remail.$error.required||
                        scope.registerForm.remail.$error.minlength||
                        scope.registerForm.remail.$error.maxlength||
                        scope.registerForm.remail.$error.email)) {
                        timer = setTimeout(function () {
                            $http(
                                {
                                    method: 'POST',
                                    url: 'http://127.0.0.1:5000/auth/email_check',
                                    // params: {"email": scope.register_user.email}
                                    data: {"email": scope.register_user.email}
                                }
                            ).then(
                                function (response) {
                                    if (response.status === 200 && response.data["status"] === "yes") {
                                        ctrl.$setValidity('email_error', true);
                                        $log.info(response);
    
                                    }
                                    else {
                                        ctrl.$setValidity('email_error', false);
                                        $log.info(response);
                                    }
                                },
                                function (reason) {
                                    ctrl.$setValidity('email_error', false);
                                    console.log(reason);
                                }
                            );
                        }, 2000)
                    }
                }).bind('keydown', function() {
                    if(scope.registerForm.remail.$error.email_error){
                        ctrl.$setValidity('email_error',true);
                    }
                    clearTimeout(timer);
                });
            }
        }
    });
    

    设置定时器,两秒没有键盘操作,向服务器提交一次数据,接受返回结果,html上绑定指令email-check,服务端python-flask测试代码:

    @auth.route('/email_check', methods=['POST'])
    def email_check():
        print request.json['email']
        s = [{"status": "yes"}]
        if request.json['email']:
            user = User.query.filter_by(email=request.json['email']).first()
            if user:
                s = [{"status": "no"}]
        response = make_response(jsonify(s[0]))
        response.headers['Access-Control-Allow-Origin'] = '*'
        response.headers['Access-Control-Allow-Methods'] = 'POST'
        response.headers['Access-Control-Allow-Headers'] = 'x-requested-with,content-type'
        return response
    

    实际测试结果:


    异步验证密码界面.png 调试框.png 异步验证账户服务.png

    密码验证同理

    表单提交只需要在添加action="/auth/register2""

    服务端代码:

    @auth.route('/register2', methods=['POST'])
    def register2():
        print request.form.get('remail')
        if request.form.get('remail'):
            user = User.query.filter_by(email=request.form.get('remail')).first()
            if user:
                return "email has been register!"
            else:
                user = User(email=request.form.get('remail'),
                            username=request.form.get('remail'),
                            password=request.form.get('rpassword'))
                db.session.add(user)
                db.session.commit()
                token = user.generate_comfirmation_token()
                send_email(user.email, 'Confirm your account', 'email/confirm', user=user, token=token,
                           next=request.args.get('next'))
                # send_email(current_app.config['DEFPIS_ADMIN'],'New User','email/new_user',user=user,next=request.args.get('next'))
                flash('A confirmation email has been sent to you by email!')
                return redirect(url_for('auth.login', email=request.form.get('remail'), password=request.form.get('rpassword'),remember=True))
        return "data error"
    

    为了不使错误信息全部一起弹出来,设定只有在上一个输入框填入合法,才会显示下一个输入框的错误信息,链式判断:

    <div ng-cloak ng-if="registerForm.remail.$dirty&&registerForm.remail.$invalid">...
    <div ng-cloak ng-if="registerForm.remail.$valid&&registerForm.rpassword.$dirty&&registerForm.rpassword.$invalid">...
    <div ng-cloak ng-if="registerForm.rpassword.$valid&&registerForm.cpassword.$dirty&&registerForm.cpassword.$invalid">...
    ...
    

    这样错误信息只会一个个显示,用户可以按照错误信息,一步步完成表单,避免一次性出现多个错误提示。

    小问题:表单自动补全会导致异步请求不生效。必须键盘触发向后台提交数据,应该使用监控数据变化的方式触发该事件。

    相关文章

      网友评论

        本文标题:angularjs登录注册表单实践

        本文链接:https://www.haomeiwen.com/subject/jaqyqftx.html