angularjs登录注册表单实践

使用AngularJS实现登录与注册

html和css布局

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

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


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


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

Your account is required. It is not a valid account. Your account is required to be at least 6 characters. Your account cannot be longer than 18 characters. Your account does not exist.
Your password is required. It is not a valid password. Your password is required to be at least 6 characters. Your password cannot be longer than 18 characters.

登录界面长这个样子:

登录界面.png

以下是注册页面代码:

Your account is required. It is not a valid account. Your account is required to be at least 6 characters. Your account cannot be longer than 18 characters. Your account is taken, please try another one.
Your password is required. It is not a valid password. Your password is required to be at least 6 characters. Your password cannot be longer than 18 characters. Your password is so weak, please try another one stronger.
Confirm password is required. The confirm password entered is invalid.
agreements.
You must agree with all the terms.

注册界面长这个样子:

注册页面.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上这样绑定


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

The confirm password entered is invalid.

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上这样绑定:


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

You must agree with all the terms.

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

$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"

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

...
...
... ...

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

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

你可能感兴趣的:(angularjs登录注册表单实践)