跳转到主要内容

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。

所有提交的信息确保安全。

  • 关闭 [x]

当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

所有提交的信息确保安全。

  • 关闭 [x]

Ajax 和 XML: 使用 Ajax 实现打分评级和添加评论功能

使用 Ajax 技巧在应用程序中加入友好的评级和评论功能

Jack D Herrington (jherr@pobox.com), 高级软件工程师, Leverage Software Inc.
Jack D. Herrington 是一位有着超过 20 年经验的高级软件工程师。他是 Code Generation in ActionPodcasting Hacks PHP Hacks 这三本书的作者。他还发表了 30 多篇文章。可以通过 jherr@pobox.com 与 Jack 联系。

简介: 在由人员驱动的 Web 时代,允许读者评级和评论站点内容的功能是必不可少的。通过本文探索如何使用 Ajax 在站点中加入评级和评论功能。

查看本系列更多内容

发布日期: 2007 年 8 月 23 日
级别: 中级
访问情况 : 2939 次浏览
评论: 


我们大家都喜欢评定内容的等级。我认为这是人类与生俱来的秉性。我和我的女儿都喜欢去电影院看电影;虽然她过去对电影的内容毫不讲究,不过现在却挑剔了许多,因为她已经四岁了。我曾经教过她使用 “大拇指朝上” 和 “大拇指朝下” 的评级系统 à la Ebert 和 Roeper。(她曾经为 Shrek the Third 这部电影竖起了大拇指。)我认为这就是人们乐于在因特网上评论产品和文章的原因所在。

请访问 Ajax 技术资源中心,这是有关 Ajax 编程模型信息的一站式中心,包括很多文档、教程、论坛、blog、wiki 和新闻。任何 Ajax 的新信息都能在这里找到。

RSS 订阅 Ajax 相关文章和教程的 RSS 提要

本文将介绍如何结合使用 MySQL、PHP、Prototype.js 和 Asynchronous JavaScript™ and XML (Ajax) 在站点中添加简单的评级和评论功能。

评级系统

虽然我女儿乐于使用大拇指进行评级,不过大多数人更倾向于另一种略有差别的评级系统:五星级评级系统,其中一颗星为最差,三颗星为中等。在本例中,我将使用五星级评级系统对电影进行评级。您也可以将本文中评级系统应用于需要的内容 — 如文章、产品和播客。

清单 1 显示了本例所使用的模式,其中创建了一个初始的 movies 表。这相当简单:在表中定义一个自动递增的电影 ID 和电影名称。然后,创建一个 rating 表保存电影的投票结果。这个表通过 movie_id 与 movie 表绑定在一起,表中还包含一个 rating 字段,取值范围为 1 到 5。


清单 1. rating.sql
                
DROP TABLE IF EXISTS movies;

CREATE TABLE movies (
  movie_id INTEGER NOT NULL AUTO_INCREMENT,
  name VARCHAR( 128 ) NOT NULL,
  PRIMARY KEY ( movie_id )
);

DROP TABLE IF EXISTS ratings;

CREATE TABLE ratings (
  movie_id INTEGER NOT NULL,
  rating INTEGER NOT NULL
);

如果要执行 “一人一投” 的模式,则必须在 ratings 表中添加一个用户 ID,从而确保每个人只能对一部电影评定一次。考虑到程序的简单性,我并没有实现这一功能。

要将模式导入数据库,必须先创建一个数据库,然后再添加模式。可以使用以下命令行指令完成这些操作:

% mysqladmin create comments
% mysql comments < ratings.sql

您可能需要根据您的 MySQL 安装添加登录凭证。

完成这些步骤之后,我们需要使用一个页面显示可用的电影,并为每部电影添加一个评级页面链接。清单 2 显示了这个索引页面。


清单 2. index.php
                
<html>
<body>
<?php
require_once("DB.php");

$db =& DB::Connect( 'mysql://root@localhost/comments', array() );
if (PEAR::isError($db)) { die($db->getMessage()); }

$res = $db->query( 'SELECT * FROM movies' );
while( $res->fetchInto( $row ) )
{
?>
<a href="rate.php?id=<?php echo($row[0]) ?>"><?php echo($row[1]) ?></a><br/>
<?php
}
?>
</body>
</html>

简单起见,我使用结构化查询语句(Structured Query Language,SQL)语句在 movies 表中加入了一些著名的电影。下载 部分提供了示例代码。您可以在索引页面中看到这些电影,如 图 1 所示。


图 1. 电影列表
电影列表

如果您无法通过示例代码显示出这个清单,可能您的机器未使用 PEAR 存储库安装 DB 模块。要安装它,只需在命令行中运行以下命令:

% pear install DB

现在,电影列表可以正常显示了。接下来,我们将实现电影评级页面,这个页面还可以显示当前投票的总排名和日平均排名。实现这些功能的 rate.php 页面代码如 清单 3 所示。


清单 3. rate.php
                
<?php
require_once("DB.php");

$db =& DB::Connect( 'mysql://root@localhost/comments', array() );
if (PEAR::isError($db)) { die($db->getMessage()); }

$id = $_GET['id'];
$title = '';

$res = $db->query( 'SELECT name FROM movies WHERE movie_id=?', array( $id ) );
while( $res->fetchInto( $row ) ) { $title = $row[0]; }
?>
<html>
<head>
<title><?php echo($title); ?></title>
<script src="prototype.js"></script>
<script>
function rate( value ) {
        new Ajax.Updater( 'rating', 'ratemovie.php?id=<?php echo($id)?>&v='+value );
}
</script>
</head>
<body>
<h1><?php echo($title); ?></h1>

<div id="rating">
<img src="star_off.gif" onclick="rate(1)"></img>
<img src="star_off.gif" onclick="rate(2)"></img>
<img src="star_off.gif" onclick="rate(3)"></img>
<img src="star_off.gif" onclick="rate(4)"></img>
<img src="star_off.gif" onclick="rate(5)"></img>
<br/><br/>
<?php

$res2 = $db->query(
        'SELECT count( rating ), sum(rating ) FROM ratings WHERE movie_id=?',
        $id
);
while( $res2->fetchInto( $row ) )
{
?>
Votes: <?php echo($row[0]); ?><br/>
Average Rating: <?php echo($row[1]/$row[0]); ?>
<?php
}
?>
</div>

</body>
</html>

文件顶部的代码通过传递 ID 参数获得电影标题。在脚本中间部分,我们导入了 prototype.js 库并创建了一个 rate() JavaScript 函数,这个函数将通过 Ajax 使用 Prototype 库调用 ratemovie.php 页面。然后,我们添加了一组星形图像,点击这些图像时脚本将调用 rate() 函数。

在文件底部的代码中,我们运行了一个快速查询获取投票数和指定电影的投票总数。然后,在页面中显示出这些数据,这样读者就可以知道该电影的评级情况。

清单 4 中的 ratemovie.php 脚本负责在数据库中添加评级,然后返回一些超文本标志语言(Hypertext Markup Language,HTML)代码,以替换原始页面中的投票星级和评论数。


清单 4. ratemovie.php
                
<?php
require_once("DB.php");

$db =& DB::Connect( 'mysql://root@localhost/comments', array() );
if (PEAR::isError($db)) { die($db->getMessage()); }

$v = $_GET['v'];
$id = $_GET['id'];

$sth = $db->prepare( 'INSERT INTO ratings VALUES ( ?,? )' );
$db->execute( $sth, array( $id, $v ) );
?>
<img src="star_<?php echo( ($v>0)?'on':'off' ) ?>.gif"></img>
<img src="star_<?php echo( ($v>1)?'on':'off' ) ?>.gif"></img>
<img src="star_<?php echo( ($v>2)?'on':'off' ) ?>.gif"></img>
<img src="star_<?php echo( ($v>3)?'on':'off' ) ?>.gif"></img>
<img src="star_<?php echo( ($v>4)?'on':'off' ) ?>.gif"></img>
<br/><br/>
<?php
$res2 = $db->query(
  'SELECT count( rating ), sum(rating ) FROM ratings WHERE movie_id=?',
  $id
);
while( $res2->fetchInto( $row ) )
{
?>
Votes: <?php echo($row[0]); ?><br/>
Average Rating: <?php echo($row[1]/$row[0]); ?>
<?php
}
?>

图 2 显示了运行中的评级页面。


图 2. 评级页面
The rating page

单击页面的中星形图案时,投票将添加到数据库中;星形图案、投票和平均评级的 HTML 代码会发生改变,从而反映出投票已添加。

理想情况下,我希望能够在主页上看到所有电影的评分情况。清单 5 中的新版索引页面实现了这一功能。


清单 5. index2.php
                
<html>
<body>
<table>
<?php
require_once("DB.php");

$db =& DB::Connect( 'mysql://root@localhost/comments', array() );
if (PEAR::isError($db)) { die($db->getMessage()); }

$res = $db->query( 'SELECT * FROM movies' );
while( $res->fetchInto( $row ) )
{

$res2 = $db->query(
  'SELECT count( rating ), sum(rating ) FROM ratings WHERE movie_id=?', $row[0]
);
$rating = 0.0;
while( $res2->fetchInto( $row2 ) ) { $rating = $row2[1] / $row2[0]; }
?>
<tr><td align="center">
<?php echo( $rating > 0 ? $rating : 0 ) ?>
<td><td>
<a href="rate2.php?id=<?php echo($row[0]) ?>"><?php echo($row[1]) ?></a>
</td></tr>
<?php
}
?>
</table>
</body>
</html>

图 3 中可以看出,各个电影的评级情况都在新版的索引页面中显示出来了。


图 3. 更新后的电影页面
更新后的电影页面

使用 Ajax、PHP、MySQL 和非常方便的 Prototype.js JavaScript 库实现投票模式就这么简单。

在下一个示例中,我们将实现电影评论功能。


评论

Web 上的评论系统形式各异,从极其简单的博客评论系统(可以对博客条目发表一连串的评论)到异常复杂的主题评论系统(比如 Slashdot 上的评论系统),不一而足。

本例所使用的评论系统比较简单。您可以根据需要对它进行适当的调整。

首先,在已有数据库模式中添加一个表,如 清单 6 所示。


清单 6. comments.sql
                
DROP TABLE IF EXISTS comments;
CREATE TABLE comments (
  movie_id INTEGER NOT NULL,
  email VARCHAR(255) NOT NULL,
  name VARCHAR(255) NOT NULL,
  comment TEXT NOT NULL
);

所添加的是 comments 表,这个表通过 movie_id 字段与电影关联在一起。表中定义了一个电子邮件地址、评论者名称和评论文本。这是一个相当基本的评论系统,类似于 WordPress 和 MoveableType 博客软件上的评论系统。

如果想要创建一个主题评论系统,则需要在表中添加一个自动递增的 ID 字段,然后使用一个可为空的 parent_id 字段指向各个评论的父级评论。如果 字段为空,则这个评论是顶层评论。

要在评级页面中加入评论功能,我们需要在页面底部包含一些额外的脚本。清单 7 显示了这个新的 PHP 代码。


清单 7. rate2.php
                
...
<h2>Comments</h2>
<div id="comments">
<?php
$res3 = $db->query(
  'SELECT * FROM comments WHERE movie_id=?',
  $id
);
while( $res3->fetchInto( $row3 ) )
{
?>
<div>
<a href="mailto:<?php echo($row3[1]) ?>"><?php echo($row3[2]) ?></a> says:
'<?php echo($row3[3]) ?>'
</div>
<?php
}
?>
</div>

<div style="margin-top:20px;">Add your own comment:</div>

<form id="cform">
<input type="hidden" name="id" value="<?php echo($id)?>">
<table>
<tr><td>Name:</td><td><input type="text" name="name"></td></tr>
<tr><td>Email:</td><td><input type="text" name="email"></td></tr>
<tr><td>Comment:</td><td><textarea name="comment" id="comment_text"></textarea></td></tr>
</table>
</form>
<button onclick="addcomment()">Add Comment</button>

<script>
function addcomment()
{
  new Ajax.Updater( 'comments', 'addcomment.php',
  {
    method: 'post',
    parameters: $('cform').serialize(),
    onSuccess: function() {
       $('comment_text').value = '';
    }
  } );
}
</script>
</body>
</html>

脚本首先使用数据库中关于该电影的评论填充 “comments” <div> 标记。 然后,在标准 HTML <form> 标记中包含评论名称、评论者电子邮件和评论内容的字段。form 标记中还包含一个隐藏值(当前所查看电影的 ID),从而评论添加脚本知道应该将这个评论指派给哪部电影。

表单下面的 Add Comment 按钮将调用 addcomment() JavaScript 函数。这个函数使用了 Prototype.js 库中的 Ajax.Updater 对象来调用 addcomment.php 脚本。它使用了非常方便的 serialize() 函数对名称、电子邮件地址和评论内容进行打包,这个函数也是由 Prototype.js 提供的。

如果评论成功,代码会重置评论字段的文本,这样可以允许用户随意添加任意数量的评论,而不用重新输入名称和电子邮件地址。

清单 8 显示了 addcomment.php 脚本。


清单 8. addcomment.php
                
<?php
require_once("DB.php");

$id = $_POST['id'];

$db =& DB::Connect( 'mysql://root@localhost/comments', array() );
if (PEAR::isError($db)) { die($db->getMessage()); }

$sth = $db->prepare( 'INSERT INTO comments VALUES ( ?, ?, ?, ? )' );
$db->execute( $sth, array( $id,
  $_POST['email'], $_POST['name'], $_POST['comment' ] ) );

$res = $db->query('SELECT * FROM comments WHERE movie_id=?', $id );
while( $res->fetchInto( $row ) )
{
?>
<div>
<a href="mailto:<?php echo($row[1]) ?>"><?php echo($row[2]) ?></a> says:
'<?php echo($row[3]) ?>'
</div>
<?php
}
?>

首先,脚本将 POST 数据中指定的评论内容添加到数据库中。然后,将所有的评论内容作为 HTML 代码输出,其方式与原始评级页面一样,只不过这次页面中额外显示了用户所提供的评论。

新的评级页面如 图 4 所示。


图 4. 更新后的评级页面,具有评论功能。
新的评级页面

这个评论系统可以即时地向用户反馈信息。用户单击 Add Comment 时,页面会立即更新评论内容。系统还可以显示出其他用户在这期间提交的评论。

您可能需要扩展这个示例,使服务器可以自动更新评论部分。当然,您大可不必调用 addcomment.php 来完成这点。可以使用另一个脚本来返回评论,而不必添加新脚本。为此,Prototype.js 提供了一个 Ajax.PeriodicalUpdater 类,使用这个类中定义的 ID、刷新率和 URL 可以根据需要刷新 Web 页面中的任何部分。


添加 RSS 提要

扩展该示例的另一种简单的方法是将电影列表的内容和排名作为 RSS 导出。实现这一功能的代码如 清单 9 所示。


清单 9. rss.php
                
<?php
header( "content-type:text/xml" );
?>
<rss version="0.91">
<channel>
<title>Movie rankings</title>
<link>http://localhost/comments/rss.php</link>
<?php
require_once("DB.php");

$db =& DB::Connect( 'mysql://root@localhost/comments', array() );
if (PEAR::isError($db)) { die($db->getMessage()); }

$res = $db->query( 'SELECT * FROM movies' );
while( $res->fetchInto( $row ) )
{

$res2 = $db->query(
  'SELECT count( rating ), sum(rating ) FROM ratings WHERE movie_id=?', $row[0]
);
$rating = 0.0;
while( $res2->fetchInto( $row2 ) ) { if ( $row2[0] > 0 ) $rating = $row2[1] / $row2[0]; }
?>
<item>
<title><?php echo($row[1]) ?> - 
<?php echo( $rating > 0 ? $rating : 0 ) ?> stars</title>
<link>http://localhost/commentsts/rate2.php?id=<?php echo($row[0]) ?></link>
<description><?php echo($row[1]) ?></description>
</item>
<?php
}
?>
</channel>
</rss>

清单 9 中的代码的作用类似于使用 HTML 格式导出数据。它使用 <title><description><link> 标记指向各个电影页面,而不是 HTML 中的 <table><tr><td> 标记。当我在 Firefox 浏览器中打开这个页面时,所显示的页面如 图 5 所示。


图 5. 浏览器中的 RSS 提要
浏览器中的 RSS 提要

很容易吧!从 PHP 中获取 XML 提要就是这么简单。

当我使用以下命令行在本地运行代码时:

% php rss.php
            

我可以直接看到 RSS XML。清单 10 显示了这个 RSS 的一部分。


清单 10. RSS excerpt
                
<rss version="0.91">
<channel>
<title>Movie rankings</title>
<link>http://localhost/comments/rss.php</link>
<item>
<title>Star Wars - 4.5 stars</title>
<link>http://localhost/commentsts/rate2.php?id=1</link>
<description>Star Wars</description>
</item>
<item>
...


结束语

最近,关于用户生成内容的话题格外引人关注,尤其是它如何增强 Web 2.0 的力量这方面。与本文中示例一样,您可以使用 Prototype.js 库之类的优秀工具轻易地构建 Ajax 应用程序。对网站内容的评级和评论功能确实是一种极好的用户生成内容的形式。



下载

描述名字大小下载方法
本文的源代码x-ajaxxml5-code.zip22 KBHTTP

关于下载方法的信息


参考资料

学习

获得产品和技术

讨论

关于作者

Jack D. Herrington 是一位有着超过 20 年经验的高级软件工程师。他是 Code Generation in ActionPodcasting Hacks PHP Hacks 这三本书的作者。他还发表了 30 多篇文章。可以通过 jherr@pobox.com 与 Jack 联系。

关于报告滥用的帮助

报告滥用

谢谢! 此内容已经标识给管理员注意。


关于报告滥用的帮助

报告滥用

报告滥用提交失败。 请稍后重试。


developerWorks:登录


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 使用条款

 


当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。

请选择您的昵称:

当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

(长度在 3 至 31 个字符之间)


单击提交则表示您同意developerWorks 的条款和条件。 使用条款.

 


为本文评分

评论

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=XML, Open source, Web development
ArticleID=250344
ArticleTitle=Ajax 和 XML: 使用 Ajax 实现打分评级和添加评论功能
publish-date=08232007
author1-email=jherr@pobox.com
author1-email-cc=dwxed@us.ibm.com

标签

Help
使用 搜索 文本框在 My developerWorks 中查找包含该标签的所有内容。

使用 滑动条 调节标签的数量。

热门标签 显示了特定专区最受欢迎的标签(例如 Java technology,Linux,WebSphere)。

我的标签 显示了特定专区您标记的标签(例如 Java technology,Linux,WebSphere)。

使用搜索文本框在 My developerWorks 中查找包含该标签的所有内容。热门标签 显示了特定专区最受欢迎的标签(例如 Java technology,Linux,WebSphere)。我的标签 显示了特定专区您标记的标签(例如 Java technology,Linux,WebSphere)。