1.先后台搭建javascript
开发的第一步是搭建先后台系统。搭建前台系统的时候新建了LoginController控制器和登陆界面View/Login/index.tpl。模板文件中须要引入js和css文件,这里想经过在配置文件中建立模板变量的方式简化脚本文件的引入,但在建立的过程当中遇到了问题。php
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__css
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,改进后的版本以下:html
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实现的。java
body { margin: 0; padding: 0; height: 100%; background: url(../img/background.jpg) no-repeat; background-size: 100%; }
由于我用的图片宽度太小,没法填充整个页面,我试图经过设置width: 100%来填充整个页面,结果固然是失败的,由于height和width属性是控制content的,与background无关。jquery
后一个功能是经过js实现的。最初的测试脚本以下:web
$(function(){ //登陆页背景随机 var rand = Math.floor(Math.random() * 5) + 1; $("body").css("background", "url(../img/login_bg1.jpg)"); });
刷新浏览器页面报错:ajax
注意,这里查找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(' ').removeClass('succ').addClass('failure'); }, unhighlight: function(element, errorClass) { $(element).css('border', '1px solid #ccc'); $(element).parent().find('span').html(' ').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(' ').removeClass('succ').addClass('loading'); }, complete: function(jqXHR) { if (jqXHR.responseText == 'true') { $('#username').next().html(' ').removeClass('loading').addClass('succ'); } else { $('#username').next().html(' ').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(' ').removeClass('succ').addClass('loading'); }, complete: function(jqXHR) { if (jqXHR.responseText == 'true') { $('#email').next().html(' ').removeClass('loading').addClass('succ'); } else { $('#email').next().html(' ').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); } }, });