前端动态加载帖子(AJAX+PHP)

 

实现效果:

 

前言:想了很久的一个问题,我们写博客,究竟在写什么。如果单是为了自己做笔记,那怎么写也无可厚非。如果是为了分享知识,或者纯粹就是为了满足某些自己虚荣的小心思,那我们要注重写什么呢?写一门语言中的函数怎么用?放着那么详细的官方文档不去看,为什么要看copy过来的博客呢?只是因为“懒”吗?已经接受不了“快餐文化”之外的东西了吗?我不认为几句话可以把这个问题解决的有多完美,同样的问题转交给我们这些看博客的人,我们想看什么呢?

 

忽略上一段话,进入正题:

网络虚拟社交,可以说是我们社交的主要方式了。毕竟隔了两层屏幕,自信心仿佛也提升了一个level,尤其对于一些“嘴工”能力比“手工”能力强的人们来说。

 

我们刷微博,逛朋友圈,翻翻空间。一些需要“抬头”看的消息,让我们“脖子酸痛”,就怼一怼。那些“低头”不屑看的消息,就嘲讽一番,获取一些愉悦感。

 

有这么一个功能,我们会注意到。就是每次页面显示的消息只有那么几条,看完之后需要下拉刷新,才能再获得几条消息。为什么需要设计这么一个功能呢?

 

现在需要用你的大脑模拟这样一种情况:数据库中有一万条数据,你要全部渲染到页面上供读者查阅。假设一条数据渲染1s(当然没这么慢),一万条数据渲染完成后,用户已经睡着了。换种实现方式,每次渲染五条数据,用户可以瞬间(相对于一万来说)获得消息进行查看,如果需要,就再加载五条。一来减轻了服务器传送数据的压力,二来也减轻了前端渲染的压力,同时节省了用户获取信息的等待时间。

 

实现这个功能,我们首先想到的可能就是如何实现动态的修改页面这个功能。你可能想到了各种各样的实现方式,我们玩这一种:AJAX 。想要详细了解,菜鸟教程:

https://www.runoob.com/ajax/ajax-tutorial.html

 

AJAX是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面。

 

有一个经典的AJAX使用实例,在 2005 年,Google 通过其 Google Suggest 使 AJAX 变得流行起来。Google Suggest 使用 AJAX 创造出动态性极强的 web 界面:当你在谷歌的搜索框输入关键字时,JavaScript 会把这些字符发送到服务器,然后服务器会返回一个搜索建议的列表。(我们使用百度时,关键字嵌入后,出现的推荐搜索条目,同为此种情况。)

 

AJAX 不是新的编程语言,而是一种使用现有标准的新方法。AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。

 

以上三段摘自菜鸟,依旧建议抽出一些时间简单的去了解一下教程。无需记住,单了解到AJAX是个什么东西,可以解决什么问题即可。当你再次遇到问题时,就多了一个工具,尽管没有记住工具的详细使用方法,但这从来不是解决不了问题的原因。

 

XMLHttpRequest 是 AJAX 的基础,一个简单的例子(同样来自菜鸟):

<script>
function loadXMLDoc()
{
	var xmlhttp;
	if (window.XMLHttpRequest)
	{
		//  IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
		xmlhttp=new XMLHttpRequest();
	}
	else
	{
		// IE6, IE5 浏览器执行代码
		xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
	}
	xmlhttp.onreadystatechange=function()
	{
		if (xmlhttp.readyState==4 && xmlhttp.status==200)
		{
			document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
		}
	}
	xmlhttp.open("GET","/try/ajax/ajax_info.txt",true);
	xmlhttp.send();
}
</script>

来简单分析下,开头的一对判断if...else,是为了区别不同类型新老浏览器。对此无兴趣点,可屏蔽。末尾的两句open和send,即完成向服务器发送请求的功能。open的参数分别是:请求方法,请求文件所在位置,是否采用异步。

 

而请求完毕获取数据后,要做的工作就是onreadystatechange函数。其中的一个if判断,表示响应已就绪,其他详细参数值参看教程。获得来自服务器的响应,使用 XMLHttpRequest 对象的 responseText 或 responseXML 属性(两属性区别参看教程)。

 

可以看到onreadystatechange(每当 readyState 改变时,就会触发 onreadystatechange 事件)执行的逻辑功能就一句,即通过DOM将id为myDiv的标签内容修改为“ajax_info.txt”的内容。

 

放回到实际问题中,每次动态加载,就可以通过ajax将每条帖子添加进一个div里面

<!doctype html>
<html>
<head>
<!-- Load jQuery library -->
<script type="text/javascript" src="scripts/jquery-1.6.2.min.js"></script>
<script type="text/javascript">
function loadXMLDoc()
{
  var xmlhttp;
  if (window.XMLHttpRequest)
  {
    //  IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
    xmlhttp=new XMLHttpRequest();
  }
  else
  {
    // IE6, IE5 浏览器执行代码
    xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
  }
  xmlhttp.onreadystatechange=function()
  {
    if (xmlhttp.readyState==4 && xmlhttp.status==200)
    {
      //向myDiv中添加请求获取的数据
    }
  }
  globalvar++;
  xmlhttp.open("GET","URL",true);
  xmlhttp.send();
}
</script>
</head>
<body>

<!--This is the START of the content-->

  <div class="comments-block" id="myDiv">
        <div class="spacer"></div>
        <div class="comment"> <img class="avatar" alt="" src="images/identify.png" width="50" height="35" />
          <div class="comment-info"> <a class="post-author">John Doe</a>
            <p>January 21, 2011</p>
          </div>
          <div class="comment-body">
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In in vestibulum eros. Praesent at cursus orci. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam vitae sagittis dolor. Proin iaculis suscipit quam non suscipit. Vestibulum vestibulum semper tortor...</p>
        </div>
        <div class="spacer"></div>

        <div class="comment"><img class="avatar" alt="" src="images/identify.png" width="50" height="35" />
          <div class="comment-info"> <a class="post-author">Jane Doe</a>
            <p>January 21, 2011</p>
          </div>
          <div class="comment-body">
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In in vestibulum eros. Praesent at cursus orci. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam vitae sagittis dolor. Proin iaculis suscipit quam non suscipit. Vestibulum vestibulum semper tortor...</p>
        </div>
        <div class="spacer"></div>
        </div>
        </div>
  </div>

  <button type="button" onclick="loadXMLDoc()">加载内容</button>

</body>
</html>

不要因为习惯快餐文化,看到这么多字就烦了。仔细看下,并没有多少东西。script里的函数就不用说了,刚刚一直再聊它呢。怎么换了个地就不认得了。body中,结构也很简单一个id为myDiv的div中放着两个帖子的表示形式(开头图中的两个帖子)。帖子需要变化的只有三个:姓名,时间和帖子内容(当然你要按照自己的功能去设计帖子的格式)。或许写成这样好看些:

<body>

<!--This is the START of the content-->

  <div class="comments-block" id="myDiv">

    姓名1 时间1 内容1

    姓名2 时间2 内容2

  </div>

  <button type="button" onclick="loadXMLDoc()">加载内容</button>

</body>

一个button用来触发事件。onreadystatechange中需要做的,前面也说了,就是往div中添加帖子嘛。

 

如果使用DOM,你可以采用这种方式:

document.getElementById("myDiv").innerHTML+="添加内容";

当然看着有一丢丢蠢笨蠢笨的。再或者使用DOM元素添加子节点的方式:

document.getElementById("myDiv").appendChild(newchild);

这之前,你需要创建好你的newchild。

 

我这里用了JQuery,无论看起来,还是用起来,都比较的简单明了:

<!-- Load jQuery library -->
<script type="text/javascript" src="scripts/jquery-1.6.2.min.js"></script>

<script type="text/javascript">
function loadXMLDoc()
{
  var xmlhttp;
  if (window.XMLHttpRequest)
  {
    //  IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
    xmlhttp=new XMLHttpRequest();
  }
  else
  {
    // IE6, IE5 浏览器执行代码
    xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
  }
  xmlhttp.onreadystatechange=function()
  {
    if (xmlhttp.readyState==4 && xmlhttp.status==200)
    {
      $("#myDiv").append(xmlhttp.responseText);
    }
  }
  xmlhttp.open("GET","URL",true);
  xmlhttp.send();
}
</script>

前端完成,现在的问题是,得到xmlhttp.responseText的内容。

 

前后串联一下,此例子中的每条帖子只需要三条内容:姓名、时间和内容。数据库表(comment)可以这样设计:

             

(当然,如果你是基于文件的存储方式,前后设计对应就好。)

 

我们要做的就是将数据一条条读取出来,分别将姓名、时间和内容插入到前端设计的帖子格式里(即下方白色部分),并全部返回给前端。

<div class="comment"> <img class="avatar" alt="" src="images/identify.png" width="50" height="35" />
        <div class="comment-info"> <a class="post-author">John Doe</a>
          <p>January 21, 2011</p>
        </div>
        <div class="comment-body">
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In in vestibulum eros. Praesent at cursus orci. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam vitae sagittis dolor. Proin iaculis suscipit quam non suscipit. Vestibulum vestibulum semper tortor...</p>
        </div>
        <div class="spacer"></div>
</div>

以下为php实现:ajax_info.php

<?php
$servername = "localhost";
$username = "数据库用户名";
$password = "数据库密码";
$dbname = "所调用数据库名称";

// 创建连接
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
    die("连接失败: " . $conn->connect_error);
} 
 
$sql = "SELECT username, time, content FROM comment";
$result = $conn->query($sql);
 
if ($result->num_rows > 0) {
    // 输出数据
    while($row = $result->fetch_assoc()) {
        echo '<div class="comment"><img class="avatar" alt="" src="images/identify.png" width="50" height="35" />
          <div class="comment-info"> <a class="post-author">'.$row["username"].'</a>
            <p>'.$row["time"].'</p>
          </div>
          <div class="comment-body">
            <p>'.$row["content"].'</p>
        </div>
        <div class="spacer"></div>
        </div>';
    }
} else {
    echo "0 结果";
}
$conn->close();
?>

从comment表中读取出来的一条条数据,循环遍历将每一个字段插入到相应的位置构成一个完整的帖子格式。此处的“插入”功能采用了字符串拼接的方式,稍微逊色一些。你可以采用任何字符串格式化方法,只要你喜欢。关于字符串拼接,这里有一些问题,稍后指出。

 

获取数据的功能实际完毕,xmlhttp.open("GET","ajax_info.php",true)也就可以确定下来了呀。

 

剩下最后一个功能点,如何每次显示指定条数(比如五条)?

 

SQL语句的设计无需多谈,我们能瞬间想到limit。limit使用语法:

select * from table_name limit [index,] num;

从查询数据集中的index位置起,取出num条数据。

 

num为5,已经确定了。index怎么办呢?我们第一次点击按钮,index应该为0。第二次点击按钮,index应该为5。怎么办呢?其实在考虑功能的时候,你就会发现,index就是个计数器呀,它和点击的次数有关:index = click * 5。

 

前端给ajax_info.php发送请求的时候,多发送个参数不就完了~ 问题解决:

<script type="text/javascript">
var globalvar = -1;
function loadXMLDoc()
{
  var xmlhttp;
  if (window.XMLHttpRequest)
  {
    //  IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
    xmlhttp=new XMLHttpRequest();
  }
  else
  {
    // IE6, IE5 浏览器执行代码
    xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
  }
  xmlhttp.onreadystatechange=function()
  {
    if (xmlhttp.readyState==4 && xmlhttp.status==200)
    {
      $("#myDiv").append(xmlhttp.responseText);
    }
  }
  globalvar++;
  xmlhttp.open("GET","ajax_info.php?q="+window.globalvar*5,true);
  xmlhttp.send();
}
</script>

声明一个全局变量globalvar当做计数器,每次请求将其当做参数q的值一起发送(当然可以使用post方式发送,详细查看ajax教程)。

 

ajax_info.php的sql查询语句也需要稍加改变:

<?php
$servername = "localhost";
$username = "xxx";
$password = "xxx";
$dbname = "xxx";
$q = $_GET["q"];
// 创建连接
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
    die("连接失败: " . $conn->connect_error);
} 
 
$sql = "SELECT username, time, content FROM comment limit ".$q.",5";
$result = $conn->query($sql);
 
if ($result->num_rows > 0) {
    // 输出数据
    while($row = $result->fetch_assoc()) {
        echo '<div class="comment"><img class="avatar" alt="" src="images/identify.png" width="50" height="35" />
          <div class="comment-info"> <a class="post-author">'.$row["username"].'</a>
            <p>'.$row["time"].'</p>
          </div>
          <div class="comment-body">
            <p>'.$row["content"].'</p>
        </div>
        <div class="spacer"></div>
        </div>';
    }
} else {
    echo "0 结果";
}
$conn->close();
?>

全部完成,当你运行完毕后,可能会发现没有文章开头的那个图片那么漂亮,那是因为好多的样式我并没有加入,一来看着乱,二来没啥用,去自定义设计就好。

 

如果每次加载,想要实现显示最新帖子(即显示最后插入到table中的数据)的功能呢?那就把sql的查询结果集倒序一下呗~(可利用table中的id字段: select * from commont order by id desc limit 5;)

 

剩下最后一个点需要关注,就是前面所说字符串的拼接问题。简化一下:

 echo ''.$row["username"].''.$row["time"].''.$row["content"].'';

其实就是这么一块东西,这里面有一些隐含的风险需要注意,引号问题。如果content的值是I'm fine。这个时候进行字符串拼接就会有问题。那个单引号会和其后的.''第一个单引号闭合(分号之前),从而致使语句多了一个单引号而出现语法错误。

 

双引号同样原理。

 

还有一个风险,就是XSS注入。不详细谈论,与本文章无关,感兴趣请搜索查阅。简单来说,如果拼接的内容中有<>,这部分东西就会被浏览器当做标签来解释,如果内容中有句script脚本代码,随便解释后,就不一定会发生什么事情了。可能你的ip,你的cookie,你经常浏览的网站,你的账号信息已经悄悄地发给了远在天边的某人。你的电脑可能被悄悄装了后门,等你不在的时候,就会被“打开”......

 

阻止方式有很多,我这里简单说一种,就是在往数据库里写入数据的时候,先把内容给它过滤一遍。

$message = addslashes(htmlspecialchars($_POST['cf_message']));

htmlspecialchars是将html一些预定义字符实体化,预定义的字符是:

  • & (和号) 成为 &amp;

  •        "   (双引号) 成为 &quot;
  •        '   (单引号) 成为 &#039;
  •        < (小于) 成为 &lt;
  •        > (大于) 成为 &gt;

addslashes() 函数返回在预定义字符之前添加反斜杠的字符串。预定义字符是:

  • 单引号(')

  • 双引号(")

  • 反斜杠(\)

  • NULL

做了这些基本处理,再往数据库里面放,就会少一分顾虑。

 

开头留下的问题,仍旧没有解决。我也不认为那是个问题,文章中所有略带嘲讽语气的话语,皆是节目需要,请勿对号入座。如果您已经坐下了,那就坐着吧,我也不会赶您走。(手动狗头)

 

初学者,文章撰写不同之处,欢迎评论指出。

 

全篇完。

 

(注:此篇文仅为玩具,请勿过于信真。)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值