1. 登陆验证码

当用户登陆的时候我们希望也弹出验证码,有两种方法可以实现:一是再增加一个弹出验证码的dialog,二是和注册共用一个验证码dialog。第一种方法有大量重复代码,所以我们使用第二种方法。首先,为了让javascript区分是登陆还是注册,我们给验证码表单增加一个自定义属性:form-click。

login.js<form id="verify_register" form-click=""><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>

现在login表单和register表单的验证中submitHandler只做两件事情:给verify_register的form-click属性赋值,打开verify_register窗口:

login.js$('#login').validate({submitHandler: function(form){$("#verify_register").attr('form-click', 'login');$("#verify_register").dialog('open');},

login.js $("#register").dialog({width: 430,height: 370,modal: true,resizable: false,autoOpen: false,title: "注册新用户",closeText: "关闭",buttons: [{text: "提交",click: function(e) {$(this).submit();},}],}).validate({submitHandler: function() {$("#verify_register").attr('form-click', 'register');$("#verify_register").dialog('open');},

验证码的检测以及注册或登陆成功后的跳转都放到verify_register的submitHandler中进行处理:

login.jssubmitHandler: function(form) {if ($("#verify_register").attr('form-click') == 'register') {$('#register').ajaxSubmit({url: ThinkPHP["MODULE"] + "/User/register",type: "POST",data: {verify: $('#verify').val(),},beforeSubmit: function() {$('#loading').dialog('open');},success: function(responseText) {if (responseText) {$('#loading').css('background', 'url(' + ThinkPHP['IMG'] + '/reg_success.png) no-repeat 20px center').html('数据新增成功...');setTimeout(function() {$('#register').dialog('close');$('#verify_register').dialog('close');        //关闭注册界面$('#loading').dialog('close');        //关闭提示界面$('#verify_register').resetForm();            //还原注册表单$('#span.star').html('*').removeClass('succ');        //恢复*去掉对号}, 1000);}},});} else if ($("#verify_register").attr('form-click') == 'login') {$(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);}},});}
},

2. 自动登录

如要要实现自动登录,那么必须保存用户的登陆信息,这有两种方式:cookie和session。前者保存在客户端,安全性较低;后者存储在服务器端,安全性高,但是会占用服务器资源。这里我们先采用session的方式。

保存方式已经决定了,接下来就要考虑保存哪些内容。我们保存用户的id,最后登录的IP和登录时间。为了存储这些信息,我们需要对原来的用户表进行调整,添加两个字段:last_login和last_ip。

login.js中的一个小错误导致在这里浪费了半个小时,特意做个记录,以免以后又犯同样的错误。

login.js

} else if ($("#verify_register").attr('form-click') == 'login') {$(form).ajaxSubmit({    //此处应该是$('#login')url: ThinkPHP['MODULE']  + '/User/login',type: 'POST',beforeSubmit: function() {$('#loading').dialog('open');},success: function(responseText) {if (responseText == -9) {

继续上面的话题,更新用户信息和写入session的动作都是在UserModel的login方法中完成的:

UserModel.class.php$user = $this->field('id, password, last_login, last_ip')->where($map)->find();
if ($user['password'] == $password) {//更新登陆信息$update = array('id'             => $user['id'],'last_login'    => NOW_TIME,'last_ip'        => get_client_ip(1),    //参数1表示返回long型数字
    );$this->save($update);//登陆信息写入SESSION$auth = array('id'            => $user['id'],'last_login'    => $user['last_login'],'last_ip'        => $user['last_ip'],);session('user_auth', $auth);return $user['id'];
} else {return -9;    //用户密码错误
}

在一个需要登录的系统中,很多操作是只有登录用户才可以做的,所以在许多地方我们都需要验证用户是否已经登录,这是通过检测session是否存在实现的。我们这一部分提取出来建立一个新的HomeController,IndexController、UserController和LoginController都继承HomeController。

HomeController.class.php<?php
namespace Home\Controller;
use Think\Controller;class HomeController extends Controller {protected function login() {if (session('?user_auth')) {return 1;} else {$this->redirect('Login/index');        //redirect方法自带U方法
        }}
}

IndexController.class.php<?php
namespace Home\Controller;class IndexController extends HomeController {public function index() {if ($this->login()) {echo "Login successfully";}}
}

接下来我们要把用户信息写入COOKIE,因为COOKIE是保存在客户端的,为了增强安全性,我们需要对其进行加密存储。流程如下:

1. 在配置文件里设置一个密钥COOKIE_KEY

2. 在加密函数中,首先对密钥值执行sha1,将结果与用户名进行异或,再将结果用base64加密

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',),//cookie秘钥'COOKIE_KEY'    => 'www.juedi.com',
);

function.php//COOKIE加解密,0加密,1解密
function encrypttion($username, $type = 0) {$key = sha1(C('COOKIE_KEY'));if (!$type) {$username = base64_encode($username ^ $key);} else {$username = base64_decode($username) ^ $key;}return $username;
}

现在来添加自动登录功能。

首先需要在模板上添加一个checkbox:

index.tpl<span class="username"><input type="text" name="username" placeholder="用户名/邮箱"><label class="auto" for="auto"><input type="checkbox" id="auto" name="auto">自动登录</label>
</span>

UserController和UserModel中的login方法也需要做相应的改动:

UserModel.class.php//用户名加密写入COOKIE
if ($auto == 'on') {cookie('auto', encryption($user['username']), 3600 * 24 * 30);
}

在HomeController的login方法中首先就需要判断是否自动登录:

HomeController.class.phpclass HomeController extends Controller {protected function login() {//处理自动登录,当cookie存在且session不存在的情况下,生成sessionif (!is_null(cookie('auto')) && !session('?user_auth')) {$username = encryption(cookie('auto'), 1);$map['username'] = $username;$db = D('user');$user = $db->field('id, username, last_login, last_ip')->where($map)->find();//登陆信息写入SESSION$auth = array('id'            => $user['id'],'username'        => $user['username'],'last_login'    => $user['last_login'],'last_ip'        => $user['last_ip'],);session('user_auth', $auth);}//判断session是否存在if (session('?user_auth')) {return 1;} else {$this->redirect('Login/index');        //redirect方法自带U方法
        }}

LoginController的login方法也要做相应的改动:

LoginController.class.phppublic function index() {if (!session('?user_auth')) {        //只有当session不存在时才可以看到登录界面$this->display();} else {$this->redirect('Index/index');}}

3. 绑定IP验证登录

如果有人恶意地将cookie复制到另外一台电脑上,那么他就可以实现自动登录。为了防止cookie被盗用,我们把IP地址也加密写入cookie,在自动登录的时候验证是不是用户登录时的IP地址。

UserModel.class.php//用户名和IP加密写入COOKIE
if ($auto == 'on') {cookie('auto', encryption($user['username']. '|' .get_client_ip()), 3600 * 24 * 30);
}

HomeController.class.phpif (!is_null(cookie('auto')) && !session('?user_auth')) {$value = explode('|', encryption(cookie('auto'), 1));list($username, $ip) = $value;if ($ip == get_client_ip()){$map['username'] = $username;$db = D('user');$user = $db->field('id, username, last_ip')->where($map)->find();//自动登录更新登陆信息$update = array('id'             => $user['id'],'last_login'    => NOW_TIME,);$db->save($update);//登陆信息写入SESSION$auth = array('id'            => $user['id'],'username'        => $user['username'],'last_login'    => NOW_TIME,'last_ip'        => $user['last_ip'],);session('user_auth', $auth);}
}

4. 微博主页设计

我们把微博主页也分成header、main和footer三个部分。

在这里我们先复习一下CSS的定位position。position主要有四个属性:static(默认属性)、absolute、relative、fixed,区别如下:

  1. static:默认值。没有定位,元素出现在正常的流中(忽略 top, bottom, left, right 或者 z-index 声明)。
  2. absolute:脱离了文档流,生成绝对定位的元素,相对于 static 定位以外的第一个父元素进行定位。元素的位置通过 "left", "top", "right" 以及 "bottom" 属性进行规定。
  3. relative:不脱离文档流,生成相对定位的元素,相对于其正常位置进行定位。因此,"left:20" 会向元素的 LEFT 位置添加 20 像素。
  4. fixed:脱离了文档流,生成绝对定位的元素,相对于浏览器窗口进行定位。元素的位置通过 "left", "top", "right" 以及 "bottom" 属性进行规定。

对于脱离了文档流的元素(即使用了absolute或fixed定位的元素),它相邻元素的margin不再相对于此元素。还需注意left、top、right、bottom属性和margin的区别。根据position属性的不同,left等值相对的对象也不同,而margin一直是相对于相邻元素的。

此外这一部分我们还用到了CSS3的box-shadow属性,关于该属性的使用可以参考 http://www.w3cplus.com/content/css3-box-shadow。

在做导航的时候遇到了一个问题今天没能解决:

可以在上图看到每个导航项目都太靠下了。

接着昨天的问题往下说。

进过今天下午半个多小时的仔细研究,终于解决了昨天出现的问题,特意将解决过程记录在此,以备参考。

首先,从图中可以很明显地看出li元素超出了header的下边界,其实这里还有一个很容易被忽视的问题,那就是header_main有点儿靠右。

我给ul加上一个float:left:

#header ul {float: left;
}

然后通过firebug选取ul元素如下图:

我突然发现ul居然有16px的上下margin,在index.css开头我明明已经把ul的margin都设为0了呀?!

//起始CSSbody, h1, h2, h3, h4, h5, h6, ol, ul, p, form {margin: 0;padding: 0;
}

再仔细一看,终于发现了问题所在:注释!

对,就是开头的”//起始CSS“使上面的CSS设置没有生效,因为在CSS中注释只能用/* */。改成如下样式就好了:

/*起始CSS*/body, h1, h2, h3, h4, h5, h6, ol, ul, p, form {margin: 0;padding: 0;
}

现在又出现了一个新问题:文字太靠上了。我们想让链接垂直居中,这就需要用到line-height属性了。line-height有一个特性,叫做垂直居中性,把line-height值设置为height一样大小的值可以实现单行文字的垂直居中。

又有一个问题:当鼠标放到导航链接上时,我们想让它的背景颜色有42px的高度。这就需要将a元素设置为display:block:

最终的CSS代码如下:

index.css#header .nav {float: left;height: 42px;margin: 0 0 0 30px;
}#header ul li {float: left;margin-left: 5px;height: 42px;line-height: 42px;}#header ul li a {display: block;padding: 0 10px;font-size: 16px;color: #fff;text-decoration: none;
}#header ul li a:hover {background: #333;
}#header ul li a.selected {background: #333;
}

现在我们来实现“消息”和“账号”的弹出菜单功能:

index.tpl<li class="app">消息<dl class="list"><dd><a href="#">@到我的</a></dd><dd><a href="#">收到的评论</a></dd><dd><a href="#">发出的评论</a></dd><dd><a href="#">我的私信</a></dd><dd><a href="#">系统消息</a></dd><dd><a href="#" class="line">发私信>></a></dd></dl>
</li>

index.css#header .app {padding: 0 10px;position: relative;cursor: pointer;
}#header dl.list {width: 100px;background: #fff;border: 1px solid #666;position: absolute;top: 42px;left: -50px;display: none;
}#header dl.list a {color: #444;height: 30px;        /*覆盖掉继承的height和line-height*/line-height: 30px;
}#header dl.list a.line {border-top: 1px solid #eee;
}

index.js$(function() {$('.app').hover(function(){$(this).css({background: '#444',        //注意,千万不要用分号,属性值一定加引号!!!color: '#666',}).find('.list').show();}, function(){$(this).css({background: '#666',        //注意,千万不要用分号,属性值一定加引号!!!color: '#fff',}).find('.list').hide();});
});

现在主页的框架基本已经搭好了,我们现在把里面经常需要用到的东西分离出来,做成模板使用。

首先我们建立两个文件夹:Public和Base。Public里存放各个模板文件,Base中存放引用模板文件的文件,index.tpl文件只需要继承common.tpl即可。

5. 退出及跳转页

当用户退出登录的时候,我们应该删除用户的session,如果用户选择了自动登录,那么还应该删除用户的cookie,然后跳转到登录页面。

UserController.class.php

//退出登录
public function logout() {//清除sessionsession(null);//清理自动登录生成的cookiecookie('auto', null);$this->success('退出成功', U('Login/index'));
}

现在只要把链接加到微博首页就可以了。

index.tpl<li class="app">账号<dl class="list"><dd><a href="#">个人设置</a></dd><dd><a href="#">排行榜</a></dd><dd><a href="#">申请认证</a></dd><dd><a href="{:U('User/logout')}" class="line">退出</a></dd></dl>
</li>    

下面来设计错误和成功后的跳转页,首先在配置文件里定义两个变量:

config.php//错误跳转模板
'TMPL_ACTION_ERROR'        => 'Public/jump',//成功跳转模板
'TMPL_ACTION_SUCCESS'    => 'Public/jump',

在设计跳转页的过程中有几个问题需要解决:1. 文字居中显示;2. 文字前加图标,文字与图标在同一水平位置;

第一个问题的解决方法是给父元素增加padding,让文字到垂直居中,然后用text-align:center使文字水平居中:

jump.tpl.info {margin: 100px auto;padding: 200px 0 0 0;height: 300px;width: 1200px;background: #fafafa;text-align: center;
}

第二个问题是通过设置背景图片的位置解决的:

jump.tpl.error {background: url(__PUBLIC__/{:MODULE_NAME}/img/jump_error.png) no-repeat left bottom;
}.success {background: url(__PUBLIC__/{:MODULE_NAME}/img/jump_success.png) no-repeat left bottom;
}

6. 微博发布区设计

现在可是设计微博的发布区。

这一部分主要是在main区域,我们把它分成main_left和main_right两个部分。其中main_right的css代码如下:

index.css#main .main_right {float: right;width: 300px;background: #d0d0d0;
}

我们可以看到背景颜色只应用到了文字所在的一行,如果我们想让背景颜色充满整个区域,那就需要给区域加个height:

index.css#main .main_right {float: right;width: 300px;min-height: 800px;background: #d0d0d0;
}

因为左侧区域是微博的发布区,所以会有很多内容,当内容超过了该区域的高度时就会出问题:

可以看到,超出的内容到了main区域的下方,致使footer的内容挤到了右边。

这个问题可以通过javascript解决,代码如下:

index.js//高度保持一致
if ($('.main_left').height() > 800) {$('.main_right').height($('.main_left').height());$('#main').height($('.main_left').height());
}

这里还有一个问题,当我们向下拉滚动条时,提交按钮会到导航栏的上方,如下图所示:

这个可以通过z-index解决:

index.js#header {position: fixed;    width: 100%;height: 42px;top: 0px;        /*top定义了一个定位元素的上外边距边界与其包含块上边界之间的偏移*/background: #666;z-index: 9999;
}

界面设置基本做好了,接着要实现一些小功能。

第一个功能就是限制用户的输入在140个字以内,并且数字随着用户的输入变化,如下图:

这个是通过javascript实现的:

index.js//微博输入内容计算字个数
$('.weibo_text').on('keyup', weibo_num);function weibo_num() {var total = 280;var len = $(this).val().length;var temp = 0;if (len > 0) {for (var i = 0; i < len; i++) {if ($(this).val().charCodeAt(i) > 255) {temp += 2;} else {temp ++;}}var result = parseInt((total - temp) / 2);$('.weibo_num').html('您还可以输入<strong>' + result + '</strong>个字');}
}

7. 引入表情插件

这一节我们在微博发布区引入一款jquery表情插件,过程比较简单,就是把css、js文件放到相应目录,从原来的index.html文件里复制一些内容到我们的index.tpl就可以了。

不过,在这里还是出现了一个小问题。

当我们添加表情的时候,字数显示并没有减少,我们需要修改js文件:

index.js//微博输入内容得到光标计算字个数
$('.weibo_text').on('focus', weibo_num);

这里又出现了一个新问题,第一次添加表情的时候字数不会减少,直到再次添加字数才开始变化:

8. 微博发布及表分析

首先我们需要新建一个表用来存储用户发布的微博及其它一些信息

这里需要注意的是上面的content_over字段。由于varchar查询起来速度比较慢,所以这里我们用char类型存储微博内容。因为char最多只能存储255个字符,所以我们把280-255=25个字符存到content_over中。

今天终于解决了一个困扰我多日的问题。虽然最后发现是我的粗心造成的,但是还得记录一下。

错误还是firebug发现的:

点击上图中的绿色部分可以进入jquery.js查看:

从这儿可以开出问题出在val()方法上,elem没有nodeName。nodeName是HTML元素的一个属性,elem没有这个属性就说明它不是HTML元素,或者它是undefined或null。我们可以看一下:

index.jsfunction weibo_num() {alert(this[0]);    //查看this[0],也就是elem var total = 280;var len = $(this).val().length;var temp = 0;if (len > 0) {for (var i = 0; i < len; i++) {if ($(this).val().charCodeAt(i) > 255) {temp += 2;} else {temp ++;}}

结果如下图所示:

果然是undefined。为什么会是这个值呢?

仔细检查weibo_num函数,我发现了问题所在:$(this)!!!

这里应该用$('.weibo_text')!改过来之后一切恢复正常。

转载于:https://www.cnblogs.com/xianglongsdu/p/6027864.html

ThinkPHP开发博客系统笔记之二相关推荐

  1. WEB安全之PHP安全开发 博客系统(二):前台js登陆验证、套用模板主体修改登陆和后台样式

    WEB安全之PHP安全开发 博客系统(二):前台js登陆验证.套用模板主体修改登陆和后台样式 前台验证 模板的套用 后台模板的套用 前台验证 做自动提交 点击登陆,自动提交 如果等于false,不会提 ...

  2. 微信小程序云开发博客系统源代码,让写博客像发朋友圈一样简单,含使用部署教程

    博客就两种:一是随笔,记录自己的成长历程,二是有目的的发文,例如搬运各种网赚文,我想大部分朋友做博客的初衷都是有一块自己的心灵净土,于是催生了wxapp-blog这款小程序. 完整代码下载地址:微信小 ...

  3. Node项目实战开发-博客系统

    Nodejs项目实战开发-博客系统(已完结) 个人博客系统 欢迎访问我的博客~ MaXiaoYu's Bolg 前言: 开发技术 技术 版本 Node ^14.3.0 ejs ^3.1.3 expre ...

  4. 使用 ThinkJS + Vue.js 开发博客系统

    编者注:ThinkJS 作为一款 Node.js 高性能企业级 Web 框架,收到了越来越多的用户的喜爱.今天我们请来了 ThinkJS 用户 @lscho 同学为我们分享他基于 ThinkJS 开发 ...

  5. 全栈之巅-NodeJs(AdonisJs)+VueJs开发带完整后台管理UI的博客系统笔记

    NodeJs(AdonisJs)+VueJs开发带完整后台管理UI的博客系统 全栈之巅B站视频教程:https://www.bilibili.com/video/BV1AW411f7Ae adonis ...

  6. php开发博客系统源码,php简单博客系统

    [实例简介] php简单博客系统,是基于php+mysql组合的简单系统,下来看看吧 [实例截图] [核心代码] webstar ├── web_star │   ├── code.php │   ├ ...

  7. 开发博客系统SpringBoot+Vue教程

    目录 DAY1 [创建项目] [mybatis-plus] MyBatisPlusConfig类 MyBatis-Plus分页插件原理

  8. 基于Spring+SpringMVC+MyBatis博客系统的开发教程(十一)

    第11课:博客书写页面--KindEditor 富文本编辑器 富文本编辑器 KindEditor KindEditor 是一套开源的 HTML 可视化编辑器,可支持文字编辑.emoji 表情和图片上传 ...

  9. 和lock一起学beego 博客系统开发为例(六)

    为什么80%的码农都做不了架构师?>>>    接着上篇来写<和lock一起学beego 博客系统开发为例(五)> 这篇主要完成以下事项: 下篇我们要完成下面三个任务: ...

  10. 和lock一起学beego 博客系统开发为例(五)

    为什么80%的码农都做不了架构师?>>>    接着上篇来写<和lock一起学beego 博客系统开发为例(四)> 这篇主要完成以下事项: 下篇我们要完成下面三个任务: ...

最新文章

  1. 6、android传递数据之剪切板传递数据
  2. iOS开发之使用XMPPFramework实现即时通信(二)
  3. 用户密码登录改造实现
  4. MFC的GDI绘制坐标问题
  5. 分布式和微服务区别_深度解析spring cloud分布式微服务的实现
  6. jzoj3056-数字【数位dp,统计,容斥】
  7. spring框架做全局异常捕获_@ControllerAdvice注解(全局异常捕获)
  8. C++多线程编程 (1)
  9. codeigniter中 get_instance()的应用
  10. 2016 ECCV论文 《Peak-Piloted Deep Network for Facial Expression Recognition》
  11. [单片机框架][os层] freertos 中间件 公共函数
  12. WordPress纯代码高仿 无觅相关文章 图文模式功能
  13. layui数据表格导入Excel,后端打印乱码
  14. 自己动手学TCP/IP--ICMP(ping报文)
  15. 【Web技术】网站留言系统开发,及留言信息实时发送至指定邮箱
  16. 解决word在输入文字后公式自动矮的问题,同时实现公式自动居中,编号居右
  17. ICPLAZA凭BFT+POS快速“出圈” 打造更繁荣的生态系统
  18. Android 传感器之《加速传感器》——摇一摇功能
  19. 因为计算机中丢失6595,windows 10 安装CVE-2021-34527漏洞补丁后,开机任务栏丢失,补丁无法卸载...
  20. 【EI快速高录用】这可能是近2年发表SCI论文的最好机会!

热门文章

  1. 在spring-boot中使用@ConfigurationProperties
  2. 从分析性数据库ADS中导出数据
  3. java计算一个日子距离_java计算两地距离(公里)
  4. cmd 根据计算机名查ip地址_如何查找和更改Mac上的IP地址
  5. 脉冲控制仪C语言程序,可编程脉冲控制仪
  6. windows 编译 使用bin lib include_YOLOv3-tiny在VS2015上使用Openvino部署
  7. mybatis plugins_[Mybatis]-[基础支持层]-插件-多个插件执行顺序
  8. 【渝粤教育】国家开放大学2018年秋季 2312T旅行社经营管理 参考试题
  9. 【渝粤教育】国家开放大学2018年春季 7396-21T法学基础知识 参考试题
  10. 【渝粤教育】国家开放大学2018年秋季 1117t机电控制与可编程序控制 参考试题