菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
145
0

ThinkPHP开发博客系统笔记之一

原创
05/13 14:22
阅读数 95988

1.前后台搭建

开发的第一步是搭建前后台系统。搭建前台系统的时候新建了LoginController控制器和登录界面View/Login/index.tpl。模板文件中需要引入js和css文件,这里想通过在配置文件中创建模板变量的方式简化脚本文件的引入,但在创建的过程中遇到了问题。

Home/Conf/config.php
<?php return array( 'TMPL_PARSE_STRING' => array( '__CSS__' => '__PUBLIC__/Home/css', '__JS__' => '__PUBLIC__/Home/js', '__IMG__' => '__PUBLIC__/Home/img', ), );
View/Login/index.tpl
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>微博系统——登录界面</title> <script type="text/javascript" src="__JS__/jquery.js"></script> <script type="text/javascript" src="__JS__/jquery.ui.js"></script> <script type="text/javascript" src="__JS__/login.js"></script> <link rel="stylesheet" href="__CSS__/jquery.ui.css"> <link rel="stylesheet" href="__CSS__/login.css"> </head> <body> </body> </html>

结果__JS__等几个变量在模板文件中无法正确解析。原因是__PUBLIC__是模板替换变量,只有出现在模板文件中时才会被替换为对应的字符串。而__ROOT__、__APP__、__MODULE__、__CONTROLLER__、__ACTION__、__SELF__既是模板替换变量,也是系统常量,它们可以应用在模板文件和配置文件中,所以这里可以用__ROOT__

Home/Conf/config.php
<?php
return array(
    'TMPL_PARSE_STRING'    => array(
        '__CSS__'    =>    __ROOT__.'/Public/Home/css',
        '__JS__'    =>    __ROOT__.'/Public/Home/js',
        '__IMG__'    =>    __ROOT__.'/Public/Home/img',
    ),
);

这里还可以用系统常量MODULE_NAME代替模块名称Home,改进后的版本如下:

 

Home/Conf/config.php

<?php
return array(
    'TMPL_PARSE_STRING'    => array(
        '__CSS__'    =>    __ROOT__.'/Public/'.MODULE_NAME.'/css',
        '__JS__'    =>    __ROOT__.'/Public/'.MODULE_NAME.'/js',
        '__IMG__'    =>    __ROOT__.'/Public/'.MODULE_NAME.'/img',
    ),
);

 

2. 登录页设计

 登录页的功能之一就是自动缩放和随机变换的背景,前一个功能是通过CSS3的新属性background-size实现的。

body {
    margin: 0;
    padding: 0;
    height: 100%;
    background: url(../img/background.jpg) no-repeat;
    background-size: 100%;
}

因为我用的图片宽度过小,无法填充整个页面,我试图通过设置width: 100%来填充整个页面,结果当然是失败的,因为heightwidth属性是控制content的,与background无关。

后一个功能是通过js实现的。最初的测试脚本如下:

$(function(){
    
    //登录页背景随机
    var rand = Math.floor(Math.random() * 5) + 1;
    $("body").css("background", "url(../img/login_bg1.jpg)");
});

刷新浏览器页面报错:

注意,这里查找login_bg1.jpg的路径是相对于index.php的,因为index.php已位于网站根目录www,所以它的上级目录还是www。

这里的url路径是否可以使用__PUBLIC__呢?答案是否定的。因为模板替换只会发生在模板文件中,在js脚本中无法替换。但我们可以在模板文件中定义js变量,这样在引用该脚本中就可以使用这些变量了。

Home/View/Login/index.tpl

<script type="text/javascript">
    var ThinkPHP = {
        "IMG" : "__PUBLIC__/{:MODULE_NAME}/img",
    };
</script>
login.js

$(function(){
    
    //登录页背景随机
    var rand = Math.floor(Math.random() * 5) + 1;
    $("body")
.css("background", "url(" + ThinkPHP['IMG']+ "/login_bg" + rand +".jpg) no-repeat")
.css("background-size" , "100%"); });

这个地方还有一个小问题,就是url不能写成如下形式:

$(function(){
    
    //登录页背景随机
    var rand = Math.floor(Math.random() * 5) + 1;
    $("body").css("background", "url(ThinkPHP['IMG']/login_bg1.jpg)");    
});

因为Javascript中引号中的都是字符串常量,将ThinkPHP['IMG']放在引号中就不会转换为它所代表的变量了。

登录页面中不可或缺的元素就是登陆表单。登陆form的各元素在页面上布置好之后,先用jquery ui将type=submit的input元素转换为按钮:

login.js

$(function(){
    
    //登录页按钮
    $("#login input[type='submit']").button();
});

设置好各元素的css之后我发现submit按钮的位置有点儿靠上,需要通过定位让它的位置下移一些,并用:hover实现鼠标移动到它上面时的动画效果:

login.css

#login input[type="submit"] {
    position: relative;
    top: -4px;
    
    width: 150px;
    height: 50px;
    
    font-family: 黑体;
    font-size: 24px;
    
    background-color: #c3c3c3;
}

#login input[type="submit"]:hover {
    background-color: #3c3c3c;
}

 上面的main部门又加了一个注册和找回密码链接后就开始设计页面的底部,也就是footer部门。这里footer要实现一个透明的功能,我直接在footer上进行CSS的设计,结果footer里的文字也变透明了,这不是我想要的结果。所以我把里面的文字移出来,放到一个class=“footer_text”的p标签中。

Login/index.tpl

<div id="footer"></div>
<p class="footer_text">Juedi's blog</p>
login.css

#footer {
    position: absolute;
    bottom: 0;
    
    width: 100%;
    height: 40px;
        
    opacity: 0.4;
    background: #000;
}

.footer_text {
    position: absolute;
    bottom: 0;
    
    width: 100%;
    
    text-align: center;
    font-size: 13px;
    color: #000;
}

 下面就开始设计新用户注册界面了,最初的版本如下:

<div id="register">
            <form>
                <p>
                    <label for="user">账号:</label>
                    <input type="text" name="user" class="text" id="user" placeholder="昵称,不小于两位!">
                    <span class="star">*</span>
                    <label for="password">密码:</label>
                    <input type="password" name="password" class="text" id="password" placeholder="密码,不小于6位!">
                    <span class="star">*</span>
                    <label for="email">邮箱:</label>
                    <input type="email" name="email" class="text" id="email" placeholder="邮箱,用于找回密码!">
                    <span class="star">*</span>
                </p>
            </form>
        </div>

结果界面如下:

很显然是哪里出了问题。问题就在于label、span和input都是行内元素,它们不会自动换行,所以需要就它们放在一个块元素里面,这里我们用的是p,然后就正常了。

<div id="register">
            <form>
                <p>
                    <label for="user">账号:</label>
                    <input type="text" name="user" class="text" id="user" placeholder="昵称,不小于两位!">
                    <span class="star">*</span>
                </p>
                <p>
                    <label for="password">密码:</label>
                    <input type="password" name="password" class="text" id="password" placeholder="密码,不小于6位!">
                    <span class="star">*</span>
                </p>
                <p>
                    <label for="email">邮箱:</label>
                    <input type="email" name="email" class="text" id="email" placeholder="邮箱,用于找回密码!">
                    <span class="star">*</span>
                </p>
            </form>
        </div>

 

3. 创建用户表

现在开始创建用户表,第一个版本的表结构如下:

这个表有几个需要改进的地方。首先,create可以改为int类型,方便在web程序里操作。其次,这个表里有的字段是char类型,有的字段是varchar类型。char类型是固定长度的,可能会浪费一些空间,但查询速度快,varchar正好相反。所以,我们考虑把经常需要查询到的username、email改为char类型。如果一个表里既有char也有varchar,那么它的查询速度就会收到影响,所以我们这里把intro单独拿出来放到一个新表里,两个表通过外键关联,并且在username、email和uid上都建立unique索引。最终两个表如下:

 

4. AJAX注册及自动完成

这里主要应用了jquery validate插件来实现注册信息的ajax方式提交

$("#register").dialog({
        width: 430,
        height: 330,
        modal: true,
        resizable: false,
        autoOpen: false,
        title: "注册新用户",
        closeText: "关闭",
        buttons: [{
            text: "提交",
            click: function(e) {
                $(this).submit();
            },
        }],
        
    }).validate({
        submitHandler: function(form) {
            $(form).ajaxSubmit({
                url: ThinkPHP["MODULE"] + "/User/register",
                type: "POST",
            });
        },
    });

为了访问User/register,我们定义了ThinkPHP["MODULE"]变量

index.tpl

<script type="text/javascript">
    var ThinkPHP = {
        "IMG" : "__PUBLIC__/{:MODULE_NAME}/img",
        "MODULE" : "__MODULE__"
    };
</script>

最开始我们把用户注册逻辑放在了UserController中,但是这样程序的结构不够清晰,应该将其放到UserModel中,由Model来处理业务逻辑,Controller的作用主要是处理用户提交的数据,这里注意不要忘记在UserController.class.php中use Home\Model\UserModel。

UserModel.class.php

<?php
namespace Home\Model;
use Think\Model;

class UserModel extends Model {
    
    protected $_auto = array(
            array("password", "sha1", self::MODEL_BOTH, "function"),
            array("create", "time", self::MODEL_INSERT, "function"),
        );
        
    //注册一个用户
    public function register($username, $password, $email) {
        $data = array(
            'username' => $username,
            'password' => sha1($password),
            'email'       => $email,
            'create'   => time(),
        );
        
        if ($this->create($data)) {
            $uid = $this->add($data);
            return $uid? $uid : 0;
        }
    }
}

 

5. 服务器端验证

服务器端的验证应用了ThinkPHP框架中模型的自动验证功能:

UserModel.class.php

//用户表自动验证
protected $_validate = array(
    array('username', '2, 20', '用户名长度不合法', self::EXISTS_VALIDATE, 'length'),
    array('password', '6, 30', '密码长度不合法', self::EXISTS_VALIDATE, 'length'),    
);
......

if ($this->create($data)) {
$uid = $this->add($data);
return $uid? $uid : 0;
} else {
return $this->getError();
}

 

验证错误信息(如上面的"用户名长度不合法")可以通过模型的getError()方法得到,但是getError只会返回第一个验证的错误信息,因为验证到第一个不符合条件的项目后就不再继续验证了。可以通过打开批量验证功能,是所有表项都得到验证,此时getError返回的是一个数组:

UserModel.class.php

//打开批量验证功能
protected $patchValidate = true;

......

if ($this->create($data)) {
    $uid = $this->add($data);
    return $uid? $uid : 0;
} else {
    print_r($this->getError());
}

设置好以上自动验证后,输入用户名和密码的时候测试总是报错:

原因是我们在自动完成里设置了对密码进行hash,所以hash后的密码长度都是40,超过了自动验证里的长度限制30。但是,通过阅读《ThinkPHP3.2.2完全开发手册》,我发现自动验证是在自动完成之前,应该不会出现上面的问题才对啊?!

今天终于找到了原因:

UserModel.class.php

//
注册一个用户 public function register($username, $password, $email) { $data = array( 'username' => $username, 'password' => sha1($password), 'email' => $email, 'create' => time(), ); if ($this->create($data)) { $uid = $this->add($data); return $uid? $uid : 0; } else { print_r($this->getError()); } }

上面对password执行了sha1,导致了长度为40,去掉sha1就正常了。

前面的自动验证的错误信息返回的都是字符串,其实这个错误最终要返回给客户端,所以最好用数字代替字符串,这样还需要关闭批量验证功能:

UserModel.class.php

//打开批量验证功能
//protected $patchValidate = true;
    
//用户表自动验证
protected $_validate = array(
    //-1, 用户名长度不合法
    array('username', '2, 20', -1, self::EXISTS_VALIDATE, 'length'),
    //-2, 密码长度不合法
    array('password', '6, 30', -2, self::EXISTS_VALIDATE, 'length'),
    //-3, 密码和密码确认不一致
    array('repassword', 'password', -3, self::EXISTS_VALIDATE, 'confirm'),
    //-4, 邮箱格式不正确
    array('email', 'email', -4, self::EXISTS_VALIDATE),
    //-5, 用户名被占用
    array('username', '', -5, self::EXISTS_VALIDATE, 'unique', self::MODEL_INSERT),
    //-6, 邮箱被占用
    array('email', '', -6, self::EXISTS_VALIDATE, 'unique', self::MODEL_INSERT),
    );

......

if ($this->create($data)) {
    $uid = $this->add($data);
    return $uid? $uid : 0;
} else {
    return $this->getError();
    }

 

6. 客户端验证

客户端验证利用了jquery validate插件:

validate({
        submitHandler: function(form) {
            $(form).ajaxSubmit({
                url: ThinkPHP["MODULE"] + "/User/register",
                type: "POST",
            });
        },
        
        rules: {
            username: {
                required: true,
                minlength: 2,
                maxlength: 20,
            },
            password: {
                required: true,
                minlength: 6,
                maxlength: 30,
            },
            repassword: {
                required: true,
                equalTo: '#password',
            },
            email: {
                required: true,
                email: true,
            },
        },
        
        messages: {
            username: {
                required: '账号不得为空',
                minlength: $.format('账号不得小于{0}位!'),
                maxlength: $.format('账号不得大于{0}位!'),
            },
            password: {
                required: '密码不得为空',
                minlength: $.format('密码不得小于{0}位!'),
                maxlength: $.format('密码不得大于{0}位!'),
            },
            repassword: {
                required: '密码确认不得为空',
                equalTo: '密码和密码确认必须一致!',
            },
            email: {
                required: '邮箱不得为空',
                email: '邮箱格式不正确',
            },
        },
        
    });

效果如下图所示:

现在所有的错误提示信息都显示在了表单项的后面,这样很不美观,我们想把它们放到注册窗口的最上方,并重写错误信息的显示方式。

首先我们在注册表单中添加一个无序列表:

index.tpl

<
form id="register" action="123.html"> <ol class="register_errors"></ol> <p> <label for="user">账号:</label> <input type="text" name="username" class="text" id="user" placeholder="昵称,不小于两位!"> <span class="star">*</span>
</p>
......
login.js

showErrors: function(errorMap, errorList) {
    this.defaultShowErrors();
},
        
errorLabelContainer: 'ol.register_errors',

现在错误显示如下:

我们应该把每条信息放到一个单独的列表项中,添加如下代码:

showErrors: function(errorMap, errorList) {
    this.defaultShowErrors();
},
        
errorLabelContainer: 'ol.register_errors',
        
wrapper: 'li',

现在的显示效果如下:

 我们看到注册表框右边出现了一个scrollbar,错误信息的颜色也不够显眼,我们现在想把它去掉,同时让错误信息和出现错误的表单项的边框变为红色:

login.css

#register ol.register_errors
{ margin: 0; padding: 0 0 0 20px; color: red; } #register ol.register_errors li { height: 20px; }
login.js

showErrors: function(errorMap, errorList) { var errors = this.numberOfInvalids(); if (errors > 0){ $("#register").dialog('option', 'height', errors * 20 + 370); } else { $("#register").dialog('option', 'height', 370); }; this.defaultShowErrors(); }, hightlight: function(element, errorClass) { $(element).css('border', '1px solid red'); }, unhightlight: function(element, errorClass) { $(element).css('border', '1px solid #ccc'); },

 现在我们想实现另一个效果,当输入项正确的时候,表单项后面出现一个对号,错误的时候出现一个叉号,如下所示:

首先我们设计两个CSS样式:

login.css

#register span.succ {
    display: inline-block;
    
    padding: 5px;
    width: 28px;
    height: 28px;
    
    background: url(../img/success.png) no-repeat top;
}

#register span.failure {
    display: inline-block;
    
    padding: 5px;
    width: 28px;
    height: 28px;
    
    background: url(../img/failure.png) no-repeat top;
}

然后在login.js中添加如下代码:

login.js

highlight: function(element, errorClass) {
    $(element).css('border', '1px solid red');
    $(element).parent().find('span').html('&nbsp;').removeClass('succ').addClass('failure');
},

unhighlight: function(element, errorClass) {
    $(element).css('border', '1px solid #ccc');
    $(element).parent().find('span').html('&nbsp;').removeClass('star').addClass('succ');
},

 

7. Ajax验证数据

这里也是应用的validate插件的功能,基本思路如下:通过remote将数据Ajax提交给服务器,服务器调用相应的方法检查字段,返回'true'或'false'给remote。注意,remote只接受字符串true或false作为返回值,所以checkUserName和checkEmail都返回true或false。

login.js

rules: { username: { required:
true, minlength: 2, maxlength: 20, remote: { url: ThinkPHP['MODULE'] + '/User/checkUserName', type: 'POST', /* beforeSend: function() { $('#username').next().html('&nbsp;').removeClass('succ').addClass('loading'); }, complete: function(jqXHR) { if (jqXHR.responseText == 'true') { $('#username').next().html('&nbsp;').removeClass('loading').addClass('succ'); } else { $('#username').next().html('&nbsp;').removeClass('loading').addClass('failure'); } } */ }, }, password: { required: true, minlength: 6, maxlength: 30, }, repassword: { required: true, equalTo: '#password', }, email: { required: true, email: true, remote: { url: ThinkPHP['MODULE'] + '/User/CheckEmail', type: 'POST', /* beforeSend: function() { $('#email').next().html('&nbsp;').removeClass('succ').addClass('loading'); }, complete: function(jqXHR) { if (jqXHR.responseText == 'true') { $('#email').next().html('&nbsp;').removeClass('loading').addClass('succ'); } else { $('#email').next().html('&nbsp;').removeClass('loading').addClass('failure'); } } */ }, }, },
UserModel.class.php

//
验证占用字段 public function checkField($field, $type) { $data = array(); switch ($type) { case 'username': $data['username'] = $field; break; case 'email': $data['email'] = $field; break; default: return 0; } return $this->create($data)? 1 : $this->getError(); }
UserController.class.php

//
Ajax验证数据,账号返回给Ajax public function checkUserName() { if (IS_AJAX) { $user = new UserModel(); $uid = $user->checkField(I('username'), 'username'); echo $uid > 0? 'true' : 'false'; } } //Ajax验证数据,邮箱返回给Ajax public function checkEmail() { if (IS_AJAX) { $user = new UserModel(); $uid = $user->checkField(I('email'), 'email'); echo $uid > 0? 'true' : 'false'; } }

 

8. 完善及邮箱补全

到这一步,登陆界面已经快完成了,但还有几个需要完善的地方。首先我们希望在用户提交了注册信息到服务器返回这段时间能有一个提示信息,用户注册成功后也有一个提示信息,像下面这样:

这两个提示框其实是两个没有titlebar的dialog,其中第一个dialog我们是写在模板文件中的,第二个dialog是通过javascript替换第一个的图标和文字内容实现的:

index.tpl

<div id="loading">数据交互中...</div>

它的CSS代码如下:

login.css

#loading
{ font-size: 14px; font-weight: bold; color: #666; line-height: 25px; text-indent: 40px; background: url(../img/loading.gif) no-repeat 20px center; }
login.js

submitHandler: function(form) {
    $(form).ajaxSubmit({
        url: ThinkPHP["MODULE"] + "/User/register",
        type: "POST",
        beforeSubmit: function() {
            $('#loading').dialog('open');
        },
        success: function(responseText) {
            if (responseText) {
                $('#loading').css('background', 'url(' + ThinkPHP['IMG'] + '/reg_success.png) no-repeat 20px center').html('数据新增成功...');
                
            }
        },
    });
},

 现在当用户注册成功的时候会有提示信息,但是现在该信息和注册界面都不会消失,所以我们还得加上让它们消失的代码。此外,如果提示信息消失的太快会显得很突兀,所以我们给它加上一秒的延时:

login.js

success: function(responseText) { if (responseText) { $('#loading').css('background', 'url(' + ThinkPHP['IMG'] + '/reg_success.png) no-repeat 20px center').html('数据新增成功...'); setTimeout(function() { $('#register').dialog('close'); //关闭注册界面 $('#loading').dialog('close'); //关闭提示界面 $('#register').resetForm(); //还原注册表单 $('#register span.star').html('*').removeClass('succ'); //恢复*去掉对号 }, 1000); } },

对于邮箱补全功能,我直接copy了网上现成的代码:

$("#email").autocomplete({  
    delay: 0, //默认为300 毫秒,延迟显示设置。  
    autoFocus:true, //设置为true 时,第一个项目会自动被选定。  
    source: function (request, response) {  

        var hosts = ["qq.com", "163.com", "263.com", "sina.com.cn", "gmail.com", "hotmail.com"];//邮箱域名集合  

        var term = request.term; //获取用户输入的内容;  
        var name = term;  //邮箱的用户名  
        var host = "";   //邮箱的域名 例如qq.com  
        var ix = term.indexOf('@'); //@的位置  
        var result = []; //最终呈现的邮箱列表  
          
        //当用户输入的数据(email)里存在@的时候,就重新给用户名和域名赋值  
        if (ix > -1) { //如果@符号存在,就表示用户已经输入用户名了。  
            name = term.slice(0, ix);  
            host = term.slice(ix + 1);  
        }  

        if (name) { //如果name有值 即:不为空  

            var getHosts = []; //根据用户名填写的域名我们在hosts里面找到对应的域名集合  
              
            getHosts=  host ? ($.grep(hosts, function (val) { return val.indexOf(host) > -1 })) : hosts;  

            result = $.map(getHosts, function (val) { //这个val就是getHosts里的每个域名元素。  
                return name + "@" + val;  
            });                  
        }            
        result.unshift(term); // unshift方法的作用是:将一个或多个新元素添加到数组开始,数组中的元素自动后移,返回数组新长度 

        response(result);  

    }  
});  

这里有一个问题就是dialog阻止了溢出(overflow),导致自动提示的内容显示不全:

我们需要设置dialog显示溢出:

login.css

.ui-dialog {
    border: none;
    overflow: visible;
}

 

9. 弹出验证码

为了防止机器注册,我们给注册页面添加一个弹出验证码的功能。这里需要一个新的dialog,我在模板文件里新添加一个form:

index.tpl

<
form id="verify_register"> <ol class="ver_error"></ol> <p> <label for="verify">验证码:</label> <input type="text" name="verify" class="text" id="verify"> <span class="star">*</span> <a href="javascript:void(0)" class="changeimg">换一换</a> </p> <p> <img src='{:U("Login/verify",'','')}' class="changeimg verifyimg"> </p> </form>

然后我们在LoginController.class.php中添加一个verify方法,就是上面img的src中的方法:

LoginController.class.php

<?php
namespace Home\Controller;
use Think\Controller;

class LoginController extends Controller {
    public function index() {
        $this->display();
    }
    
    public function verify() {
        $verify = new \Think\Verify();
        $verify->entry(1);
    }
}

在javascript中将form变为dialog:

login.js

$("#verify_register").dialog({ width: 290, height: 300, modal: true, resizable: false, autoOpen: true, title: "请输入验证码", closeText: "关闭", buttons: [{ text: "完成", click: function(e) { $(this).submit(); }, }], });

最后为这个验证码弹出页面添加样式:

login.css
i
#verify_register input.text {
    padding: 5px;
    border: 1px solid #ccc;
    border-radius: 3px;
    width: 85px; 
    height: 25px;
    
    background: #fff;    
}

我们还需要验证码刷新的功能,这样是通过javascript实现的:

login.js

//点击更换验证码
var verifyimg = $('.verifyimg').attr('src');
$('.changeimg').click(function(){
    $('.verifyimg').attr('src', verifyimg + '?random=' + Math.random());
});

上周日添加了验证码功能后,注册表单的提交按钮突然不好用了,详细检查了login.js,依然无果。今天又查看了一下其它文件,终于找到了问题的原因,原来是UserController.class.php里一个函数写错了:

UserController.class.php

//
Ajax验证数据,邮箱返回给Ajax public function checkEmail() { if (IS_AJAX) { $user = new UserModel(); $uid = $user->checkField(I('email'), 'email'); echo $uid > 0? 'true' : 'false'; } } //Ajax验证数据,验证码返回给Ajax public function checkEmail() { //应该是checkVerify if (IS_AJAX) { if (check_verify(I('verify'))) { echo "验证码正确"; } else { echo "验证码错误"; } } }

 

10. 登陆验证

当用户登陆的时候,既可以使用用户名,也可以用邮箱,因为用户名和邮箱都是唯一的。但是这里有一个问题,那就是如果用户用邮箱作为用户名来注册,这就可能出现一个用户有两个账号的问题,所以我们需要在注册的用户名上做一些限制,使邮箱无法作为用户名来注册。方法也很简单,就是限制用户名不能包含@符号。

我们需要同时在客户端和服务器端进行检测。

客户端代码:

login.js

//
自定义验证,不得包含@符号 $.validator.addMethod('inAt', function(value, element) { var text = /^[^@]+$/i; //注意不要加引号!!! return this.optional(element) || (text.test(value)); }, '存在@符号');
login.js

rules: {
    username: {
        required: true,
        inAt: true,
        minlength: 2,
        maxlength: 20,
        remote: {
            url: ThinkPHP['MODULE']  + '/User/checkUserName',
            type: 'POST',
login.js

messages: {
    username: {
        required: '账号不得为空',
        inAt: '账号不得包含@符号',
        minlength: $.format('账号不得小于{0}位!'),
        maxlength: $.format('账号不得大于{0}位!'),
        remote: '账号被占用',
    },

现在当用户登陆的时候可以使用用户名也可以使用邮箱名,当然登陆方式还是采用ajax方式:

login.js

$('#login').validate({
    submitHandler: function(form){
        $(form).ajaxSubmit({
            url: ThinkPHP['MODULE']  + '/User/login',
            type: 'POST',
        });
    },
});

后台的登陆处理程序是UserController.class.php中的login方法:

Usercontroller.class.php

//Ajax验证数据,账号返回给Ajax
public function login() {
    if (IS_AJAX) {
        $user = new UserModel();
        $uid = $user->login(I('username'), I('password'));
        echo $uid;
    } else {
        $this->error('非法访问');
    }
}

它又调用了UserModel.class.php中的login方法:

UserModel.class.php

//登陆验证
public function login($username, $password) {
    $data = array(
        'login_username' => $username,
        'password' => $password,
    );
    
    //where条件
    $map = array();
    
    if ($this->create($data)) {
        //这里采用邮箱登陆
        $map['email'] = $username;
        $user = $this->field('id, password')->where($map)->find();
            if ($user['password'] == $password) {
                return $user['id'];
            } else {
                return -9;    //用户密码错误
            }
            
    } else {
        if($this->getError() == 'noemail') {
            //这里采用用户名登陆
            $map['username'] = $username;
            $user = $this->field('id, password')->where($map)->find();
            if ($user['password'] == $password) {
                return $user['id'];
            } else {
                return -9;    //用户密码错误
            }
            
        } else {
            echo $this->getError();
        }
    }
    
}

我们可以看到这里在处理用户名登陆和邮箱名登陆时有一部分代码是相同的,我们可以把这部分代码拿出来:

UserModel.class.php

//登陆验证
public function login($username, $password) {
    $data = array(
        'login_username' => $username,
        'password' => $password,
    );
    
    //where条件
    $map = array();
    
    if ($this->create($data)) {
        //这里采用邮箱登陆
        $map['email'] = $username;                
    } else {
        if($this->getError() == 'noemail') {
            //这里采用用户名登陆
            $map['username'] = $username;
        } else {
            echo $this->getError();
        }
    }
    
    $user = $this->field('id, password')->where($map)->find();
    if ($user['password'] == $password) {
        return $user['id'];
    } else {
        return -9;    //用户密码错误
    }
    
}

 当用户登录的时候如果登录信息不合法,我们需要显示错误信息,这里我们把信息显示在相应的input中,如下图所示:

首先我们需要改造模板页面,把username和password放到span标签中:

index.tpl

<div id="main">
    <form id="login">
        <div class="top">
            <span class="username">
                <input type="text" name="username" placeholder="用户名/邮箱">
            </span>
            <span class="password">
                <input type="password" name="password" placeholder="密码">
            </span>
            <input type="submit" name="submit" value="登录">
        </div>
        <div class="bottom">
            <a href="javascript:void(0)" id="reg_link">注册新用户</a>
            <a href="javascript:void(0)">忘记密码?</a>
        </div>
    </form>
</div>

接着设计CSS:

login.css

#login span.username, #login span.password {
    position: relative;
}

#login span.username label.error, #login span.password label.error {
    position: absolute;
    right: 20px;
    bottom: 0px;
    
    color: #f90;
}

前端验证代码如下:

login.js

$('#login').validate({
    submitHandler: function(form){
        $(form).ajaxSubmit({
            url: ThinkPHP['MODULE']  + '/User/login',
            type: 'POST',
        });
    },
    rules: {
        username: {
            required: true,
            minlength: 2,
            maxlength: 50,
        },
        password: {
            required: true,
            minlength: 6,
            maxlength: 30,
        },
    },
    messages: {
        username: {
            required: '账号不得为空',
            minlength: $.format('账号不得小于{0}位!'),
            maxlength: $.format('账号不得大于{0}位!'),
        },
        password: {
            required: '密码不得为空',
            minlength: $.format('密码不得小于{0}位!'),
            maxlength: $.format('密码不得大于{0}位!'),
        },
    },
});

 当用户点击登录按钮之后,我们需要根据ajax返回数据做出反应,这主要是通过javascript实现的:

login.js

$('#login').validate({
    submitHandler: function(form){
        $(form).ajaxSubmit({
            url: ThinkPHP['MODULE']  + '/User/login',
            type: 'POST',
            beforeSubmit: function() {
                $('#loading').dialog('open');
            },
            success: function(responseText) {
                if (responseText == -9) {
                    $('#loading').dialog('option', 'width', 200).css('background', 'url(' + ThinkPHP['IMG'] + '/warning.png) no-repeat 20px center').html('账号或密码不正确...');
                    setTimeout(function(){
                        $('#loading').dialog('close');
                        $('#loading').dialog('option', 'width', 180).css('background', 'url(' + ThinkPHP['IMG'] + '/loading.gif) no-repeat 20px center').html('数据交互中...');
                    }, 2000);
                } else {
                    $('#loading').dialog('option', 'width', 220).css('background', 'url(' + ThinkPHP['IMG'] + '/reg_success.png) no-repeat 20px center').html('登录成功,跳转中...');
                    setTimeout(function(){
                        location.href = 'http://www.baidu.com';
                    }, 1000);
                }
            },
        });

 

发表评论

0/200
145 点赞
0 评论
收藏
为你推荐 换一批