首页 > PHP资讯 > HTML5培训技术 > 个人网站留言页面(前端jQuery编写、后台php读写MySQL)_

个人网站留言页面(前端jQuery编写、后台php读写MySQL)_

HTML5培训技术
首先,上个人网站的留言页面,大家可以看看效果:留言板

前端为了省事,使用jQuery编写,后台使用php简单读写MySQL数据库。

数据库设计和实现思路

数据库创建了一个表:comments,结构如下图:

全部评论(包括文章评论回复,留言板)都写在同一张表中,不同的评论区用字段belong区分

同一个评论区里,parent为0表示为评论,parent为某值时表示为哪个评论的回复,思路不复杂。

注意,这里并不讲CSS,大家根据自己的需要定制,现在开始封装:

定下功能

我们根据自己的需要定下功能,首先我的网站并没有实现消息提醒,即时通讯的功能,所以评论回复并不会提示站长或者用户,只会对留言区产生效果,所以我们只要简单实现以下功能:

1、显示评论列表

2、能够提交评论

3、进行回复

评论类

我们将评论的功能封装成一个类,通过实例化就能创建不同的评论区,所以不难想到,

实例化的时候我们需要传入的参数可能有:评论区的id、获取评论的php地址,提交评论的php地址。

所以我们可以猜想实例化评论区的代码可能为:

var oCmt = new Comment({ parent: $('#box'),      //你想要将这个评论放到页面哪个元素中 id: 0, getCmtUrl: './php/getcomment.php', setCmtUrl: './php/comment.php'})

当然,我是在Comment类上定义一个静态方法

Comment.allocate({ parent: $('#box'), id: 0, getCmtUrl: './php/getcomment.php', setCmtUrl: './php/comment.php'})

大同小异,只是初始化的地方不同而已

构造函数

function Comment(options){ this.belong = options.id; this.getCmtUrl = options.getCmtUrl; this.setCmtUrl = options.setCmtUrl; this.lists = []; this.keys = {}; this.offset = 5;}var fn = Comment.prototype;Comment.allocate = function(options){ var oCmt = new Comment(options); if (oCmt.belong == undefined || !oCmt.getCmtUrl || !oCmt.setCmtUrl) {  return null; }; oCmt.init(options); return oCmt;};

里面的变量和方法我们慢慢解释,如果你不定义一个allocate方法,那么可以写成:

function Comment(options){ this.belong = options.id; this.getCmtUrl = options.getCmtUrl; this.setCmtUrl = options.setCmtUrl; this.lists = []; this.keys = {}; this.offset = 5; if (this.belong == undefined || !this.getCmtUrl || !this.setCmtUrl) {  return null; }; this.init(options)}var fn = Comment.prototype;

变量先不说,像我都是先写功能函数,然后需要添加属性变量再回头来添加,我们只需要看到构造函数最后执行了:

this.init(options)

从名字可以看出是初始化函数。

init函数

fn.init = function (options) { //初始化node this.initNode(options); //将内容放进容器 this.parent.html(this.body); //初始化事件 this.initEvent(); //获取列表 this.getList();};

fn为Comment.prototype,只说一次,下面就不再说了。

初始化就是有4个工作要做,从代码注释可以看出,现在一个一个讲解

initNode函数

从名字可以看出主要初始化节点或者缓存dom

fn.initNode = function(options){ //init wrapper box if (!!options.parent) {  this.parent = options.parent[0].nodeType == 1 ? options.parent : $('#' + options.parent); }; if (!this.parent) {  this.parent = $('p');  $('body').append(this.parent); } //init content this.body = (function(){  var strHTML = '

' + '

' + '' + '' + '

' + '

' + '

' + '

暂时没有评论

' + '
    ' + '

    ' + '

    ' + '

    ' + '

    ' + '

    '; return $(strHTML); })(); //init other node this.text = this.body.find('.cmt-text').eq(0); this.cmtBtn = this.body.find('.u-button').eq(0); this.noCmt = this.body.find('.no-cmt').eq(0); this.cmtList = this.body.find('.cmt-list').eq(0); this.loading = this.body.find('.u-loading1').eq(0); this.pagerBox = this.body.find('.pager-box').eq(0);};

    代码中我们可以看出:

    this.parent : 保存的是容器节点
    this.body : 保存的是评论区的html
    this.text : 保存的是评论的textarea元素
    this.cmtBtn : 保存的是提交按钮
    this.noCmt : 保存的是没有评论时的文字提醒
    this.cmtList : 保存的是列表的容器
    this.loading : 保存的是加载列表时的loading GIF图片
    this.pagerBox : 需要分页时的分页器容器

    js上没有难点,都是一些jQuery的方法

    将内容放进容器中

    this.parent.html(this.body)

    这个没什么好讲的,很简单,这时我们的评论组件应该在页面显示了,只是现在没有加载评论列表,也不能评论,下面先讲加载评论列表

    getList 函数

    首先是初始化列表,清空,显示加载gif图,隐藏没有评论的提醒字样,做好准备就发起ajax请求。

    思路是用php将该评论区的留言全部弄下来,在前端再来整理,ajax请求为:

    fn.resetList = function(){ this.loading.css('display', 'block') this.noCmt.css('display', 'none'); this.cmtList.html('');};fn.getList = function(){ var self = this; this.resetList(); $.ajax({  url: self.getCmtUrl,  type: 'get',  dataType: 'json',  data: { id: self.belong },  success: function(data){   if(!data){    alert('获取评论列表失败');    return !1;   };   //整理评论列表   self.initList(data);   self.loading.css('display', 'none');   //显示评论列表   if(self.lists.length == 0){    //暂时没有评论    self.noCmt.css('display', 'block');   }else{    //设置分页器    var total = Math.ceil(self.lists.length / self.offset);    self.pager = new Pager({     index: 1,     total: total,     parent: self.pagerBox[0],     onchange: self.doChangePage.bind(self),     label:{      prev: '<',      next: '>'     }    });   }  },  error: function(){   alert('获取评论列表失败');  } });};

    get形式,然后传送id过去,得到了的数据希望是列表数组。

    php的内容不讲,下面贴出sql语句:

    $id = $_GET['id'];$query = "select * from comments where belong=$id order by time";...$str = '[';foreach ($result as $key => $value) {  $id = $value['id'];  $username = $value['username']; $time = $value['time']; $content = $value['content']; $parent = $value['parent']; $str .= <<

    获得的是json字符串,jQuery的ajax可以将它转为json数据,获得的数据如下:

    如果加载成功,那么我们得到的是一堆的数据,我们现在是在success回调函数里,数据需要整理,才能显示,因为现在所有的评论回复都属于同一层。

    initList 函数

    fn.initList = function (data) { this.lists = []; //保存评论列表 this.keys = {}; //保存评论id和index对应表 var index = 0; //遍历处理 for(var i = 0, len = data.length; i < len; i++){  var t = data[i],   id = t['id'];  if(t['parent'] == 0){   this.keys[id] = index++;   this.lists.push(t);  }else{   var parentId = t['parent'],    parentIndex = this.keys[parentId];   this.lists[parentIndex]['response'].push(t);  } };};

    我的思路就是:this.lists放的都是评论(parent为0的留言),通过遍历获取的数据,如果parent为0,就push进this.lists;否则parent不为0表示这是个回复,就找到对应的评论,把该回复push进那条评论的response中。

    但是还有个问题,就是因为id是不断增长的,可能中间有些评论被删除了,所以id和index并不一定匹配,所以借助this.keys保存id和index的对应关系。

    遍历一遍就能将所有的数据整理好,并且全部存在了this.lists中,接下来剩下的事情就是将数据变成html放进页面就好了。

    //显示评论列表if(self.lists.length == 0){ //暂时没有评论 self.noCmt.css('display', 'block');}else{ //设置分页器 var total = Math.ceil(self.lists.length / self.offset); self.pager = new Pager({  index: 1,  total: total,  parent: self.pagerBox[0],  onchange: self.doChangePage.bind(self),  label:{   prev: '<',   next: '>'  } });}

    这是刚才ajax,success回调函数的一部分,这是在整理完数据后,如果数据为空,那么就显示“暂时没有评论”。

    否则,就设置分页器,分页器我直接用了之前封装的,如果有兴趣可以看看我之前的文章:

    面向对象:分页器封装

    简单说就是会执行一遍onchange函数,默认页数为1,保存在参数obj.index中

    fn.doChangePage = function (obj) { this.showList(obj.index);};

    showList函数

    fn.showList = (function(){ /* 生成一条评论字符串 */ function oneLi(_obj){  var str1 = '';  //处理回复  for(var i = 0, len = _obj.response.length; i < len; i++){   var t = _obj.response[i];   t.content = t.content.replace(/</g, '<');   t.content = t.content.replace(/>/g, '>');   str1 += '
  • ' + '' + t.username + ':' + '' + t.content + '
    ' + '
  • ' } //处理评论 var headImg = ''; if(_obj.username == "kang"){ headImg = 'kang_head.jpg'; }else{ var index = Math.floor(Math.random() * 6) + 1; headImg = 'head' + index + '.jpg' } _obj.content = _obj.content.replace(/</g, '<'); _obj.content = _obj.content.replace(/>/g, '>'); var str2 = '
  • ' + '

    ' + ' ' + '

    ' + '

    ' + '

    ' + '' + _obj.username + '' + '' + _obj.time + '' + '

    ' + '' + _obj.content + '' + '
      ' + str1 + '
    ' + '

    ' + '

    ' + ' ';target.parent().parent().append(oDiv);oDiv = null;target.attr('data-disabled', 'true'); //阻止重复生成html

  • 点击取消,就把刚才生成的remove掉

    var ppNode = target.parent().parent(), oRes = ppNode.find('.response').eq(0);target.parent().remove();oRes.attr('data-disabled', ''); //让回复按钮重新可以点击

    点击提交,获取一下该获取的元素,直接调用addCmt函数

    var oText = target.parent().find('.cmt-text').eq(0), parent = target.attr('data-id');this.addCmt(target, oText, parent);

    注意: parent刚才生成html时我把它存在了提交按钮的data-id上了。

    到此全部功能都实现了,希望对大家的学习有所启发。

    HTML5培训技术

    本文由欣才IT学院整理发布,未经许可,禁止转载。
    支持3不支持0