亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

個人網站留言頁面(前端jQuery編寫、后臺php讀寫MySQL)

2019-11-20 10:10:31
字體:
來源:轉載
供稿:網友

首先,上個人網站的留言頁面,大家可以看看效果:留言板

前端為了省事,使用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 = $('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);};

代碼中我們可以看出:

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 .= <<<end  {   "id" : "{$id}",   "parent" : "{$parent}",      "username" : "{$username.'",   "time" : "{$time}",   "content" : "{$content}",   "response" : []  }end;} $str = substr($str, 0, -1); $str .= ']'; echo $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 += '<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(//</;/g, '<');  _obj.content = _obj.content.replace(//>/;/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 ? 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); };})();

這個函數的參數為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));};

上面截圖來自我的個人網站,當我們點擊回復時,我們希望能有地方寫回復,可以提交,可以取消,由于這幾個元素都是后來添加的,所以我們將行為都托管到評論列表這個元素。

下面先將提交評論事件函數。

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('提交評論');  } });}

參數有3個:_btn, _text, _parent 之所以要有這三個參數是因為評論或者回復這樣才能使用同一個函數,從而不用分開寫。

點擊后就是常見的防止多次提交,檢查一下cookie中有沒有username、email等用戶信息,沒有就使用游客身份,然后處理一下內容,去去掉空白啊,/n換成 <br> 等等,檢驗過后發起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; }};

根據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

點擊取消,就把剛才生成的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上了。

到此全部功能都實現了,希望對大家的學習有所啟發。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
色综合老司机第九色激情| 亚洲第一视频在线观看| 国产啪精品视频| 国产精品久久久久久久久久久久久久| 日韩精品欧美国产精品忘忧草| 日韩av在线天堂网| 亚洲国产精品99久久| 国产欧美精品一区二区三区介绍| 亚洲精品之草原avav久久| 国产欧美日韩免费看aⅴ视频| 国产精品日韩专区| 亚洲精品久久久久久久久久久久| 国产91对白在线播放| 日韩网站免费观看| 欧美视频免费在线观看| 性色av一区二区三区| 宅男66日本亚洲欧美视频| 精品国偷自产在线视频99| 亚洲最新av在线| 日韩暖暖在线视频| 欧美在线激情视频| 日韩在线视频中文字幕| 国产欧美日韩综合精品| 蜜臀久久99精品久久久久久宅男| 久久久女女女女999久久| 欧美激情免费视频| 国产成人av在线播放| 亚洲综合中文字幕在线观看| 麻豆乱码国产一区二区三区| 欧美日韩在线视频一区二区| 91精品国产电影| 久久视频这里只有精品| 国产精品亚洲一区二区三区| 精品视频在线导航| 91欧美精品午夜性色福利在线| 国产丝袜一区二区三区免费视频| 亚洲无亚洲人成网站77777| 色噜噜亚洲精品中文字幕| 国产精品久久不能| 免费97视频在线精品国自产拍| 亚洲一区二区三区视频| 国产精品久久久久久久7电影| 日韩中文字幕网址| 日本精品视频在线播放| 97视频免费观看| 国产精品免费看久久久香蕉| 欧美国产日韩一区二区三区| 亚洲精品乱码久久久久久按摩观| 九九久久久久99精品| 一区二区三区国产视频| 久久99亚洲热视| 日韩电影大全免费观看2023年上| 国产精品免费网站| 91香蕉嫩草影院入口| 欧洲成人免费视频| 51ⅴ精品国产91久久久久久| 成人国产精品av| 国自在线精品视频| 欧美最顶级丰满的aⅴ艳星| 日日骚久久av| 亚洲精品按摩视频| 久久人91精品久久久久久不卡| 国产成人jvid在线播放| 国产在线观看精品一区二区三区| 91精品国产电影| 欧美激情一级精品国产| 欧美日韩999| 亚洲天堂免费观看| 狠狠躁夜夜躁人人爽天天天天97| 欧美高跟鞋交xxxxxhd| www亚洲欧美| 97精品伊人久久久大香线蕉| 亚洲国产欧美久久| 欧洲美女7788成人免费视频| 久久久久久久影视| 日韩电影在线观看中文字幕| 91在线观看免费高清| 精品视频在线播放色网色视频| 欧美理论在线观看| 亚洲欧美日韩精品久久亚洲区| 国产精品国产自产拍高清av水多| 久久久久久av| 久久亚洲精品视频| 成人午夜在线视频一区| 全亚洲最色的网站在线观看| 日韩av综合中文字幕| 久久伊人精品一区二区三区| 欧美激情视频给我| 久久久在线免费观看| 国产精品99久久久久久久久久久久| 亚洲人成啪啪网站| 色悠悠国产精品| 国产精品久久久久不卡| 精品成人乱色一区二区| 色偷偷偷综合中文字幕;dd| 亚洲欧美日韩天堂一区二区| 亚洲男人天天操| 欧美国产日韩二区| 日本精品一区二区三区在线播放视频| 国产免费一区视频观看免费| 亚洲欧美综合另类中字| 91精品久久久久久久久久入口| 日韩精品免费在线视频| 午夜精品蜜臀一区二区三区免费| 国产欧美 在线欧美| 国产精品欧美日韩| 亚洲www在线观看| 成人h视频在线| 久久国产加勒比精品无码| 成人有码视频在线播放| 亚洲尤物视频网| 国产欧美精品一区二区| 亚洲国产精品人人爽夜夜爽| 欧美高清电影在线看| 亚洲美女av电影| 91精品在线观| 亚洲欧美第一页| 日本伊人精品一区二区三区介绍| 亚洲石原莉奈一区二区在线观看| 欧美日韩国产专区| 久久久久成人精品| 国产精品h片在线播放| 精品国产一区二区三区久久狼黑人| 欧美日韩亚洲精品内裤| 亚洲色图国产精品| 欧美电影免费看| 国产亚洲人成网站在线观看| 成人欧美一区二区三区在线湿哒哒| 精品视频久久久久久久| 欧美日韩国产综合视频在线观看中文| 久99九色视频在线观看| 91av在线免费观看| 欧美性生交大片免网| 亚洲自拍av在线| 成人久久一区二区| 色妞一区二区三区| 高清日韩电视剧大全免费播放在线观看| 国产亚洲欧洲在线| 欧美日韩国产二区| 欧美老肥婆性猛交视频| 欧美一级淫片videoshd| 最近2019年日本中文免费字幕| 久久久久久久久网站| 国产欧美欧洲在线观看| 亚洲国产精品va在线观看黑人| 日韩性生活视频| 亚洲aⅴ日韩av电影在线观看| 欧美影院久久久| 久久天堂电影网| 久久久久免费精品国产| 国产成人精品综合久久久| 91在线观看免费观看| 久久久精品国产一区二区| 久久久欧美精品| 久久久噜噜噜久噜久久| 国产成人精品在线播放| 尤物yw午夜国产精品视频明星| 欧美亚洲另类在线| 精品亚洲精品福利线在观看| 国产精品免费一区豆花| 97视频在线观看播放| 一区二区三区四区视频| 国产日韩在线观看av| 精品国产一区二区三区四区在线观看|