博客或其它以时间为单位的内容站点的常见特性之一就是查阅旧的日志。通常在页面底部会有一个“上一页”或“下一页”的链接,用来做导航。在实现实时更新的博客之前,首先需要做如下的假定:
□ 有一个网页,其中有按时间排序的条目
□ 当滚动到页面底部时,意味着希望浏览更多的条目
□ 有一个可以读取所有条目的数据源。比如使用WordPress博客软件
这个案例的效果是,用户滚动了页面底部附近,就会自动载入其它的文章。
1. 简化的博客主题
制作WordPress主题是个相对复杂的话题,本案例中只要生成一个简化的博客主题即可:
<html> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <head> <title>Wordpress</title> <script> <!-- 脚本 --> </script> </head> <body> <div id="page"> <div id="header"> <!-- 标题 --> </div> <div id="content"> <!-- 第一篇文章 --> <div class="post"> <!-- 文章的标题 --> <h2><a href=" /test/?p=1">测试文章</a></h2> <small>October 24th, 2013</small> <div class="entry"> <!-- 文章的内容 --> </div> <p class="postmetadata"><a href="/test/?p=1#comments">评论</a></p> </div> <!-- 更多文章… --> </div> </div> </body> </html>
所有的博客内容都包含在id为”content”的<div>中,所有的文章都采用相同的结构。所以,需要构建一套简单的DOM函数来提取数据:
// 把新文章载入到 id 为 "content" 的<div>中 var content = document.getElementById("content"); // 遍历RSS feed中的所有文章 var items = rss.getElementsByTagName("item"); for ( var i = 0; i < items.length; i++ ) { // 解析出链接、标题和描述数据 var data = getData( items[i] ); // 创建一个新的<div>用来存放这篇文章 var div = document.createElement("div"); div.className = "post"; // 创建文章标题 var h2 = document.createElement("h2"); // 文章的标题和到文章正文的链接 h2.innerHTML = "<a href='" + data.link + "'>" + data.title + "</a>"; // 追加到<div>中 div.appendChild( h2 ); // 创建一个新的<div>用来存放文章内容 var entry = document.createElement("div"); entry.className = "entry"; // 添加文章内容 entry.innerHTML = data.desc; div.appendChild( entry ); // 文章评论 var meta = document.createElement("p"); meta.className = "postmetadata"; meta.innerHTML = "<a href='" + data.link + "#comments'>Comment</a>"; div.appendChild( meta ); // 追加到<div>中 content.appendChild( div ); }
2. 数据源
在WordPress中,RSS Feed的url通常类似与这样:/blog/?feed=rss,这样还不够,还需要添加一个参数:/blog/?feed=rss&paged=N,当N等于1时得到最新的10篇文章,等于2时得到它们之前的10篇。数据源的基本内容如下:
Test WordPress Web log
http://someurl.com/test/
Test Web log.
Fri, 08 Oct 2013 02:50:23 +0000
http://wordpress.org/?v=2.0
en
-
Test Post
http://someurl.com/?p=9
Thu, 07 Sep 2013 09:58:07 +0000
Mark Zuckerberg
Uncategorized
[/code]
通过对以上内容的分析,可以到一个格式良好的XML文件。下面的代码展示了用于遍历这份RSS XML文档并从中解析相关数据的必要代码:
// 遍历RSS Feed中的文章
var items = rss.getElementsByTagName("item");
for ( var i = 0; i < items.length; i++ ) {
// 从RSS Feed中的item元素中解析出标题、描述和链接
var title = elem.getElementsByTagName("title")[0].firstChild.nodeValue;
var desc = elem.getElementsByTagName("description")[0].firstChild.nodeValue;
var link = elem.getElementsByTagName("link")[0].firstChild.nodeValue;
}
[/code]
<strong>3. 监听事件</strong>
这个案例用户需要完成的交互是滚动页面的底部,所以不管浏览器的视口到哪里,必须能判断出它是否在页面的底部。要实现这一点只需要给窗口的滚动事件绑定一个事件处理函数,监听用户是否移动了页面的视口。是否移动到页面底部可以使用自定义的pageHeight(判断整个页面有多高),scrollY(当前视口的顶部滚动位置)和windowHeight(视口的高度)函数来计算获得。
// 根据用户在所处的位置判断是否应该载入更多内容
window.onscroll = function(){
// 检查视口在页面中的位置
if ( curPage >= 1 && !loading && pageHeight() - scrollY() - windowHeight() < windowHeight() ) {
// 用Ajax请求获取RSS Feed
}
};
[/code]
4. Ajax请求
使用Ajax请求动态载入文章和条目,然后将其插入到页面中。发送的请求包括:使用HTTP GET方法连接,指定下一部分文章的url,并获取url指定的XML文档。
[code lang="js"]
// 使用ajax函数来载入文章
ajax({
// 请求的是一个简单的网页,所以使用GET
type: "GET",
// RSS Feed 是XML文件类型
data: "xml",
// 获得第下一页的RSS Feed
url: "./?feed=rss&paged=" + ( ++curPage ),
// 成功获得RSS Feed
onSuccess: function( rss ){
// 通过DOM来遍历RSS Feed
}
});
[/code]
<strong>5. 完整的代码</strong>
将创建DOM的代码和RSS XML遍历代码整合在一起,再加上滚动事件的检测和Ajax请求,就完成了这个案例。即不离开当前页面的情况下持续滚动所有博客文章的能力。
// 当前的页面编号
var curPage = 1;
// 确保不会同时载入同一个页面
var loading = false;
// 根据用户在所处的位置判断是否应该载入更多内容
window.onscroll = function(){
// 载入新内容之前需要验证:
// 1) 必须确保不在内容的最后一页
// 2) 必须确保现在不是正在载入
// 3) 只在滚动到靠近页面底部才尝试载入新文章
if ( curPage >= 1 && !loading && pageHeight() - scrollY() - windowHeight() < windowHeight() ) {
// 现在开始载入新文章
loading = true;
// 使用ajax函数来载入文章
ajax({
// 请求的是一个简单的网页,所以使用GET
type: "GET",
// RSS Feed 是XML文件类型
data: "xml",
// 获得第下一页的RSS Feed
url: "./?feed=rss&paged=" + ( ++curPage ),
// 成功获得RSS Feed
onSuccess: function( rss ){
// 把新文章载入到 id 为 "content" 的<div>中
var content = document.getElementById("content");
// 遍历RSS feed中的所有文章
var items = rss.getElementsByTagName("item");
for ( var i = 0; i < items.length; i++ ) {
// 将新文章追加到文档中
content.appendChild( makePost( items[i] ) );
}
// 如果XML文档中没有任何内容,回退到最早的位置
if ( items.length == 0 ) {
curPage = 0;
}
},
// 完成请求,允许再次请求新的内容
onComplete: function(){
loading = false;
}
});
}
};
// 为一篇文章创建DOM结构的函数
function makePost( elem ) {
// 解析出链接、标题和描述数据
var data = getData( elem );
// 创建一个新的<div>用来存放这篇文章
var div = document.createElement("div");
div.className = "post";
// 创建文章标题
var h2 = document.createElement("h2");
// 文章的标题和到文章正文的链接
h2.innerHTML = "<a href='" + data.link + "'>" + data.title + "</a>";
// 追加到<div>中
div.appendChild( h2 );
// 创建一个新的<div>用来存放文章内容
var entry = document.createElement("div");
entry.className = "entry";
// 添加文章内容
entry.innerHTML = data.desc;
div.appendChild( entry );
// 文章评论
var meta = document.createElement("p");
meta.className = "postmetadata";
meta.innerHTML = "<a href='" + data.link + "#comments'>Comment</a>";
div.appendChild( meta );
return div;
}
// 遍历RSS Feed中的文章
function getData( elem ) {
// 返回的对象是个格式化良好的对象
return {
// 从RSS Feed中的item元素中解析出标题、描述和链接
title: elem.getElementsByTagName("title")[0].firstChild.nodeValue,
desc: elem.getElementsByTagName("description")[0].firstChild.nodeValue,
link: elem.getElementsByTagName("link")[0].firstChild.nodeValue
};
}
动态载入内容是Ajax的常见用途之一。这种用法既能简化用户浏览页面的过程,又能减轻服务器的负荷。本案例是一个很好的开始。
转载请注明:陈童的博客 » Ajax案例 — 实时更新博客