Heim > Web-Frontend > js-Tutorial > Hauptteil

Persönliche Website-Nachrichtenseite (Front-End-JQuery-Schreiben, Back-End-PHP-Lesen und Schreiben von MySQL)_Javascript-Kenntnisse

WBOY
Freigeben: 2016-05-16 15:02:35
Original
2372 Leute haben es durchsucht

Gehen Sie zunächst auf die Nachrichtenseite Ihrer persönlichen Website und Sie können den Effekt sehen: Message Board

Um Ärger zu vermeiden, wird das Front-End mit jQuery geschrieben und das Back-End verwendet PHP, um einfach die MySQL-Datenbank zu lesen und zu schreiben.

Ideen für Datenbankdesign und -implementierung

Die Datenbank hat eine Tabelle: Kommentare mit der unten gezeigten Struktur erstellt:

Alle Kommentare (einschließlich Antworten auf Artikelkommentare und Message-Boards) werden in derselben Tabelle geschrieben, und verschiedene Kommentarbereiche werden durch das Feld „Zugehörigkeit“ unterschieden

Wenn das übergeordnete Element im selben Kommentarbereich 0 ist, stellt es einen Kommentar dar. Wenn das übergeordnete Element ein bestimmter Wert ist, stellt es eine Antwort dar. Die Idee ist nicht kompliziert.

Beachten Sie, dass es sich hier nicht um CSS handelt. Sie können es jetzt an Ihre eigenen Bedürfnisse anpassen:

Einstellfunktion

Wir stellen die Funktionen nach unseren eigenen Bedürfnissen ein. Erstens implementiert meine Website keine Nachrichtenerinnerungs- und Instant-Messaging-Funktionen, sodass Kommentarantworten den Webmaster oder die Benutzer nicht auffordern, sondern nur Auswirkungen auf den Nachrichtenbereich haben , also müssen wir nur die folgenden Funktionen implementieren:

1. Zeigen Sie die Kommentarliste an

2. Möglichkeit, Kommentare abzugeben

3. Antworten

Kommentare

Wir kapseln die Kommentarfunktion in einer Klasse und können durch Instanziierung verschiedene Kommentarbereiche erstellen, sodass es nicht schwer ist, daran zu denken,

Zu den Parametern, die wir beim Instanziieren übergeben müssen, gehören möglicherweise: die ID des Kommentarbereichs, die PHP-Adresse zum Erhalten von Kommentaren und die PHP-Adresse zum Senden von Kommentaren.

Wir können also davon ausgehen, dass der Code zum Instanziieren des Kommentarbereichs wie folgt lauten könnte:

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

Natürlich definiere ich eine statische Methode für die Comment-Klasse

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

Nach dem Login kopieren

Größtenteils gleich, nur die Initialisierung ist anders

Konstrukteur

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;
};

Nach dem Login kopieren
Wir werden die Variablen und Methoden in

langsam erklären. Wenn Sie keine Zuweisungsmethode definieren, können Sie sie wie folgt schreiben:

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;

Nach dem Login kopieren

Reden wir nicht über Variablen. Wie ich schreibe ich immer zuerst die Funktionsfunktion und muss sie dann später hinzufügen. Wir müssen nur darauf achten, dass der Konstruktor schließlich ausgeführt wird:

this.init(options)

Wie der Name schon sagt, handelt es sich um eine Initialisierungsfunktion.

Init-Funktion

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

Nach dem Login kopieren

fn ist Comment.prototype, der nur einmal erwähnt wird und nicht noch einmal erwähnt wird.

Initialisierung bedeutet, dass 4 Aufgaben erledigt werden müssen. Wie Sie den Codekommentaren entnehmen können, werden wir sie jetzt einzeln erklären

initNode-Funktion

Aus dem Namen ist ersichtlich, dass es sich um den Hauptinitialisierungsknoten oder Cache-Dom handelt

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 = $('div');
  $('body').append(this.parent);
 }
 //init content
 this.body = (function(){
  var strHTML = '<div class="m-comment">' +
       '<div class="cmt-form">' +
        '<textarea class="cmt-text" placeholder="欢迎建议,提问题,共同学习!"></textarea>' +
        '<button class="u-button u-login-btn">提交评论</button>' +
       '</div>' +
       '<div class="cmt-content">' +
        '<div class="u-loading1"></div>' +
        '<div class="no-cmt">暂时没有评论</div>' +
        '<ul class="cmt-list"></ul>' +
        '<div class="f-clear">' +
         '<div class="pager-box"></div>' +
        '</div>' +
       '</div>' +
      '</div>';
  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);
};

Nach dem Login kopieren

Wir können dem Code entnehmen:

this.parent: Speichert den Containerknoten
this.body: Speichert den HTML-Code des Kommentarbereichs
this.text: Speichert das Textarea-Element des Kommentars
this.cmtBtn: Speichert den Senden-Button
this.noCmt: Speichert die Texterinnerung, wenn keine Kommentare vorhanden sind
this.cmtList: Der Container, der die Liste
enthält this.loading: Speichert das Lade-GIF-Bild beim Laden der Liste
this.pagerBox: Der Pager-Container, wenn Paging erforderlich ist

In js gibt es keine Schwierigkeiten, es sind alles jQuery-Methoden

Inhalt in Container legen

this.parent.html(this.body)

Dazu gibt es nichts zu sagen, es ist ganz einfach. Zu diesem Zeitpunkt sollte unsere Kommentarkomponente auf der Seite angezeigt werden, aber die Kommentarliste ist jetzt nicht geladen und es können keine Kommentare abgegeben werden Liste

getList-Funktion

Die erste besteht darin, die Liste zu initialisieren, zu löschen, das Lade-GIF-Bild anzuzeigen, die Erinnerungswörter ohne Kommentare auszublenden und eine Ajax-Anfrage zu initiieren, wenn Sie fertig sind.

Die Idee besteht darin, PHP zu verwenden, um alle Nachrichten im Kommentarbereich abzurufen und sie im Frontend zu organisieren. Die Ajax-Anfrage lautet:

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('获取评论列表失败');
  }
 });
};

Nach dem Login kopieren

Rufen Sie das Formular ab und senden Sie dann die ID daran. Es wird erwartet, dass die erhaltenen Daten ein Listenarray sind.

Ich werde nicht über den Inhalt von PHP sprechen, aber die SQL-Anweisung wird unten gepostet:

$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 .= <<<end
  {
   "id" : "{$id}",
   "parent" : "{$parent}",   
   "username" : "{$username.'",
   "time" : "{$time}",
   "content" : "{$content}",
   "response" : []
  }
end;
}

 $str = substr($str, 0, -1);
 $str .= ']';
 echo $str;

Nach dem Login kopieren

Was erhalten wird, ist eine JSON-Zeichenfolge, die mit jQuery in JSON-Daten umgewandelt werden kann. Die erhaltenen Daten lauten wie folgt:

Wenn das Laden erfolgreich ist, erhalten wir eine Reihe von Daten. Wir befinden uns jetzt in der Erfolgsrückruffunktion. Die Daten müssen sortiert werden, bevor sie angezeigt werden können, da jetzt alle Kommentarantworten zur gleichen Ebene gehören .

initList-Funktion

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);
  }

 };
};

Nach dem Login kopieren

我的思路就是: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: '>'
  }
 });
}

Nach dem Login kopieren

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

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

面向对象:分页器封装

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

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

Nach dem Login kopieren

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(/\&lt\;/g, '<');
   t.content = t.content.replace(/\&gt\;/g, '>');
   str1 += '<li class="f-clear"><table><tbody><tr><td>' +
    '<span class="username">' + t.username + ':</span></td><td>' +
    '<span class="child-content">' + t.content + '</span></td></tr></tbody></table>' +
    '</li>'
  }
  //处理评论
  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(/\&lt\;/g, '<');
  _obj.content = _obj.content.replace(/\&gt\;/g, '>');
  var str2 = '<li class="f-clear">' +
   '<div class="head g-col-1">' +
   '<img src="./img/head/' + headImg + '" width="100%"/>' +
   '</div>' +
   '<div class="content g-col-19">' +
   '<div class="f-clear">' +
   '<span class="username f-float-left">' + _obj.username + '</span>' +
   '<span class="time f-float-left">' + _obj.time + '</span>' +
   '</div>' +
   '<span class="parent-content">' + _obj.content + '</span>' +

   '<ul class="child-comment">' + str1 + '</ul>' +
   '</div>' +
   '<div class="respone-box g-col-2 f-float-right">' +
   '<a href="javascript:void(0);" class="f-show response" data-id="' + _obj.id + '">[回复]</a>' +
   '</div>' +
   '</li>';

  return str2;

 };


 return function (page) {

  var len = this.lists.length,
   end = len - (page - 1) * this.offset,
   start = end - this.offset < 0 &#63; 0 : end - this.offset,
   current = this.lists.slice(start, end);
  var cmtList = '';
  for(var i = current.length - 1; i >= 0; i--){
   var t = current[i],
    index = this.keys[t['id']];
   current[i]['index'] = index;
   cmtList += oneLi(t);
  }
  this.cmtList.html(cmtList);
 };
})();

Nach dem Login kopieren

这个函数的参数为page,就是页数,我们根据页数,截取this.lists的数据,然后遍历生成html。

html模板我是用字符串连接起来的,看个人喜好。

生成后就 this.cmtList.html(cmtList);这样就显示列表了,效果图看最开始。

现在需要的功能还有评论回复,而init函数中也只剩下最后一个initEvent

initEvent 函数

fn.initEvent = function () {
 //提交按钮点击
 this.cmtBtn.on('click', this.addCmt.bind(this, this.cmtBtn, this.text, 0));
 //点击回复,点击取消回复,点击回复中的提交评论按钮
 this.cmtList.on('click', this.doClickResponse.bind(this));
};

Nach dem Login kopieren

上面截图来自我的个人网站,当我们点击回复时,我们希望能有地方写回复,可以提交,可以取消,由于这几个元素都是后来添加的,所以我们将行为都托管到评论列表这个元素。

下面先将提交评论事件函数。

addCmt 函数

fn.addCmt = function (_btn, _text, _parent) {
 //防止多次点击
 if(_btn.attr('data-disabled') == 'true') {
  return !1;
 }
 //处理提交空白
 var value = _text.val().replace(/^\s+|\s+$/g, '');
 value = value.replace(/[\r\n]/g,'<br >');
 if(!value){
  alert('内容不能为空');
  return !1;
 }
 //禁止点击
 _btn.attr('data-disabled','true');
 _btn.html('评论提交中...');
 //提交处理
 var self = this,
  email, username;

 username = $.cookie('user');
 if (!username) {
  username = '游客';
 }
 email = $.cookie('email');
 if (!email) {
  email = 'default@163.com';
 }

 var now = new Date();

 $.ajax({
  type: 'get',
  dataType: 'json',
  url: this.setCmtUrl,
  data: {
   belong: self.belong,
   parent: _parent,
   email: email,
   username: username,
   content: value
  },
  success: function(_data){
   //解除禁止点击
   _btn.attr('data-disabled', '');
   _btn.html('提交评论');
   if (!_data) {
    alert('评论失败,请重新评论');
    return !1;
   }
   if (_data['result'] == 1) {
    //评论成功
    alert('评论成功');
    var id = _data['id'],
     time = now.getFullYear() + '-' + (now.getMonth() + 1) + '-' + now.getDate() + ' ' +
      now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds();

    if (_parent == 0) {

     var index = self.lists.length;

     if (!self.pager) {
      //设置分页器
      self.noCmt.css('display', 'none');
      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: '>'
       }
      });
     }

     self.keys[id] = index;
     self.lists.push({
      "id": id,
      "username": username,
      "time": time,
      "content": value,
      "response": []
     });
     self.showList(1);
     self.pager._$setIndex(1);

     }else {
     var index = self.keys[_parent],
      page = self.pager.__index;
     self.lists[index]['response'].push({
      "id": id,
      "username": username,
      "time": time,
      "content": value
     });
     self.showList(page);
    }

    self.text.val('');
   } else {
    alert('评论失败,请重新评论');
   }
  },
  error: function () {
   alert('评论失败,请重新评论');
   //解除禁止点击
   _btn.attr('data-disabled', '');
   _btn.html('提交评论');
  }
 });
}

Nach dem Login kopieren

参数有3个:_btn, _text, _parent 之所以要有这三个参数是因为评论或者回复这样才能使用同一个函数,从而不用分开写。

点击后就是常见的防止多次提交,检查一下cookie中有没有username、email等用户信息,没有就使用游客身份,然后处理一下内容,去去掉空白啊, 换成
等等,检验过后发起ajax请求。

成功后把新的评论放到this.lists,然后执行this.showList(1)刷新显示

php部分仍然不讲,sql语句如下:

$parent = $_GET['parent'];
$belong = $_GET['belong'];
$content = htmlentities($_GET['content']);
$username = $_GET['username'];
$email = $_GET['email'];

$query = "insert into comments (parent,belong,content,time,username,email) value ($parent,$belong,'$content',NOW(),'$username','$email')";

doClickResponse 函数

fn.doClickResponse = function(_event){

 var target = $(_event.target);

 var id = target.attr('data-id');

 if (target.hasClass('response') && target.attr('data-disabled') != 'true') {
  //点击回复
  var oDiv = document.createElement('div');
  oDiv.className = 'cmt-form';
  oDiv.innerHTML = '<textarea class="cmt-text" placeholder="欢迎建议,提问题,共同学习!"></textarea>' +
   '<button class="u-button resBtn" data-id="' + id + '">提交评论</button>' +
   '<a href="javascript:void(0);" class="cancel">[取消回复]</a>';
  target.parent().parent().append(oDiv);
  oDiv = null;
  target.attr('data-disabled', 'true');
 } else if (target.hasClass('cancel')) {
  //点击取消回复

  var ppNode = target.parent().parent(),
   oRes = ppNode.find('.response').eq(0);
  target.parent().remove();
  oRes.attr('data-disabled', '');
 } else if (target.hasClass('resBtn')) {
  //点击评论
  var oText = target.parent().find('.cmt-text').eq(0),
   parent = target.attr('data-id');
  this.addCmt(target, oText, parent);

 }else{
  //其他情况
  return !1;
 }

};

Nach dem Login kopieren

根据target.class来判断点击的是哪个按钮。

如果点击回复,生成html,放到这条评论的后面

var oDiv = document.createElement('div');
oDiv.className = 'cmt-form';
oDiv.innerHTML = '<textarea class="cmt-text" placeholder="欢迎建议,提问题,共同学习!"></textarea>' +
     '<button class="u-button resBtn" data-id="' + id + '">提交评论</button>' +
     '<a href="javascript:void(0);" class="cancel">[取消回复]</a>';
target.parent().parent().append(oDiv);
oDiv = null;
target.attr('data-disabled', 'true'); //阻止重复生成html

Nach dem Login kopieren

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

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

Nach dem Login kopieren

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

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

Nach dem Login kopieren

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

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

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage