05月
30
[译]将基于web的php程序迁移到ajax
文章分类:misc 查看次数:466 + 122
原文地址:click here
网站开发通常是杂乱的。近几年来,我们的工具箱塞满了各种各样的工具,通常他们难以理解,并且很难结合到一块。网页代码已经成为一个历史问题。一个普通的web页总是包含了html,javascript,服务端代码。用户界面交织着各种逻辑规则和客户端-服务端通信。在大多数的编成环境里,我们使用文档的API说明,所以我们只需传递几个参数,然后就能得到我们想要的结果了。而web编程,我们通常需要hack,比如生成隐藏表单或者载入新的页面,就因为一些小的改变。难道就不能将这个过程变得更加合理吗?
这篇文章彻底改变了基于数据库的表单设计。我们先来看看过时的代码——混合了html,javascript,php。然后通过先进的技术,比如ajax,和先进的工具,比如jquery,来重构这些代码。好处是
- 将动态内容与静态内容分开来
- 将内容,样式和处理过程分开来
- 通过函数来调用服务端代码
- 页面的部分内容更新,而不是重新加载整个页面
- 更快速地开发,提高了代码的可维护性
- 加速载入过程,缓存优化
过时的代码编写
首先是html,然后是表单,javascript,最后是php代码。在表单里填入几个变量,然后在提交给服务端。或者在javascript里生成一个很长的url,javascript几乎是不可调试的。核心的变量,比如"window"并不是该语言的一部分。而且还有浏览器之间的差异。幸好w3c定义了dom,而且出现了许多跨浏览器的dhtml库。
有些动态页面很简单,你查询一次数据库然后格式化输出结果,但通常比这个更复杂。通过数据库生成下拉菜单或者选择按钮。有些页面涵盖多个表单,使得维护更加麻烦,每个表单的提交将重新生成页面。
通常结构化一个应用程序包括:
- 将所有的东西放到一个script里。 第一次运行的时候,查询数据库然后生成html代码,当再次请求时,表单传递几个命令(如add,delete)和参数(如person's id)给后台的php程序,脚本修改数据库,然后修改页面的相应内容。表单的内容将反应出数据库变化的结果
- 使用两个脚本文件。 第一个查询数据库,并生成html代码。与上面的不同是:
- 表单有一个iframe页来显示动态数据
- 表单的action,存储于第二个脚本里
- 表单的target是iframe的name
第二个看起来更好一些,但也有个问题,如果一个action改变了form的几个元素,那么整个页面需要被重新载入,我们需要一个第三项选择。
新的工具箱
无论是多么小的改变,只要提交了表单,就会重新生成一个页面(iframe可以看作一个迷你页面,而且大小不可改变) ,javascript的remoting技术将使这一切变得更加完美。
我认为最有用的贡献是:
- innerHTML
- XMLHttpRequest
- AJAX
- JSON
- New JavaScript libraries
innerHTML
这个差不多是所有的时下的浏览器都支持的一个属性。有了它我们可以得到并设置它的内容,而不需要刷新页面。比如
可以修改为
obj.innerHTML = "Now you don't";
产生的结果是
虽然DOM有许多函数可以动态改变内容,但innerHTML不失为一个更快更好的方法,但很可惜innerHTML在IE浏览器的table里是只读的。
XMLHttpRequest
这是一个发送客户端请求到服务端的函数,IE5就已经包含了,几乎支持所有当前流行的浏览器。
在2005年ajax开始备受关注,由于其异步获取内容的特性。
JSON
JavaScript Object Notation,将json代码解析成javascript的数据格式,(eval(json_string)),通常比解析XML更快。
JavaScript libraries
高质量的js库已经被开发出来了,为解决浏览器兼容和提高编程效率带来了很大的方便。这里我选择jQuery(我也选择jQuery,哈哈)
因为:
- 体积小(压缩后只有19k)
- 麻雀虽小,五脏俱全
- 良好的文档说明和社区支持
- 灵活性(她的选择语法包括了CSS1-3和XPATH,方便定位页面内容)
- 结构化(非常容易扩展)
彻底改变
历史已经结束,良好的架构开始了
为了使表现更加简洁,我们的代码忽略了错误和安全问题,目的是为了展现jquery和ajax技术是如何改变历史的。
现在来定义表单的需求
1、从people表中得到数据,主键是id
2、将名字以下拉菜单的形式出现
3、让用户选择一个用户
4、在表格里显示出该用户的相关数据
版本1:原始代码
在这个初始的版本里,我们将所有的内容都放在一个php页面里。
people1.php:
$cmd = @$_REQUEST["cmd"];
$id = @$_REQUEST["id"];
mysql_connect($server, $user, $password);
mysql_select_db("test");
?>
<html>
<head><title>Old Form</title>
<script>
// Get the selected user and retrieve his/her info
function user_info(sel)
{
var opt = sel.options;
var user_id = opt[sel.selectedIndex].value;
// Construct a GET URL, or create a hidden field for "cmd"
var url = "people1.php?cmd=info&id=" + user_id;
window.location.href = url;
}
</script>
</head>
<body>
<form action="people1.php" method="post">
People<br>
<select name="people" onchange="user_info(this)">
<option value="">(select a person)
<?php
// Get all users and display every time script is called
$result = mysql_query("select id, fname, lname from people");
while ($row = mysql_fetch_array($result, MYSQL_ASSOC))
echo "<option value='$row[id]'",
$row["id"] == $id ? " selected" : "",
">$row[fname] $row[lname]\n";
?>
</select>
<?php
if ($cmd == "info")
{
$id = mysql_real_escape_string($id);
$result = mysql_query("select * from people where id='$id'");
$info = mysql_fetch_array($result, MYSQL_ASSOC);
}
else
$info = array("fname"=>" ", "lname"=>" ", "dance"=>" ", "pie"=>" ");
echo <<< END
<br>
<table border=1>
<tr>
<td>First Name</td><td>Last Name</td><td>Dance</td><td>Pie</td></tr>
<tr>
<td>$info[fname]</td>
<td>$info[lname]</td>
<td>$info[dance]</td>
<td>$info[pie]</td>
</tr>
</table>
END;
?>
</form>
</body>
</html>
这个比较容易理解和书写。但是存在着很多问题。好处是所有的代码都写在了一个文件里,坏处跟好处是同一个理由。
新设计
下面是计划:
- 将原代码分为三个文件:静态内容(html),客户端脚本文件(js),服务端代码(php)
- 在html中包含jquery和脚本文件
- 给所有动态内容添加一个特定id
- 定义js函数,来连接客户端与服务端
我们可以通过两种方法来合并服务端返回的代码和html本身的代码
- php返回格式化的html代码,然后通过innerHTML来呈现
- php返回JSON格式的内容,javascript解析并将其插入到html中
我们两个都来试试
版本2,ajax提交,html代码返回
在这个版本中,php生成options标签,返回到html,我们只需将它插入到相应的select标签就行了,现在以html代码开始,它只是个容器
people2.html
<head><title>New Form Version 1</title>
<script src="jquery.js"></script>
<script src="people2.js"></script>
</head>
<body>
People<br>
<select id="people">
</select>
<br>
<table border=1>
<thead>
<tr><td>First Name</td><td>Last Name</td><td>Dance</td><td>Pie</td></tr>
</thead>
<tbody id="info">
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
</tbody>
</table>
</body>
</html>
下面再来看看js代码,jquery的核心函数是$(),返回一个jquery object,她的参数可以有多种形式。我们只用下面两种
- $(document):选择document DOM
- $("#myid"):选择id为myid的元素
(为了帮助阅读,我已经格式化了代码)
people2.js
(
function()
{
// Call this when the DOM is ready:
$("#people").load("people2.php?cmd=init");
// Call this when a person is selected:
$("#people").change(function()
{
// get the user's id from the selected option:
var user_id = $(":selected").val();
$("#info").load("people2.php?cmd=info&id=" + user_id);
});
}
);
这就是我们所需要的所有的js代码,下面再来看看php代码,有点类似于最初的代码,但它只是输出当前的html片段。
people2.php
$cmd = @$_REQUEST["cmd"];
$id = @$_REQUEST["id"];
mysql_connect($server, $user, $password);
mysql_select_db("test");
if ($cmd == "init")
{
$result = mysql_query("select id, fname, lname from people");
echo "<option value=''>(select a person)\n";
while ($row = mysql_fetch_array($result, MYSQL_ASSOC))
echo "<option value='$row[id]'>$row[fname] $row[lname]\n";
}
elseif ($cmd == "info")
{
$id = mysql_real_escape_string($id);
$result = mysql_query("select * from people where id='$id'");
$info = mysql_fetch_array($result, MYSQL_ASSOC);
echo <<< END
<tr>
<td>$info[fname]</td>
<td>$info[lname]</td>
<td>$info[dance]</td>
<td>$info[pie]</td>
</tr>
END;
}
?>
版本3:ajax提交,JSON返回
在这个版本里,php通过查询数据库建立了一个数组然后以JSON的格式返回,jquery将这个json字符串转换为jquery object,然后将它作为参数传给回调函数。然后通过这个函数来生成html,这个跟people2差不多。只不过名不一样
people3.html
<head><title>New Form Version 1</title>
<script src="jquery.js"></script>
<script src="people3.js"></script>
</head>
<body>
People<br>
<select id="people">
</select>
<br>
<table border=1>
<thead>
<tr><td>First Name</td><td>Last Name</td><td>Dance</td><td>Pie</td></tr>
</thead>
<tbody id="info">
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
</tbody>
</table>
</body>
</html>
下面我们将用不同的方法来填充内容,在这个版本里,我们调用getJSON ,通过三个参数
- The URL
- A dictionary of name:value pairs
- A JavaScript callback function
一个get url将会通过url和name参数生成,返回的JSON字符串,将被转换为 JavaScript object,并传递给回调函数
people3.js
(
function()
{
// Call this when the DOM is ready:
$.getJSON("people3.php",
{ cmd : "init" },
make_menu);
// Call this when a person is selected:
$("#people").change(function()
{
var user_id = $(":selected").val();
$.getJSON("people3.php",
{ cmd : "info", id: user_id },
make_info);
});
}
);
function make_menu(obj)
{
var str = "";
var len = obj.length;
str += "<option value=''>(select a person)\n";
for (var i = 0; i < len; i++)
{
var user = obj[i];
str += "<option value='" + user["id"] + "'>" +
user["fname"] + " " +
user["lname"] + "\n";
}
$("#people").html(str);
}
function make_info(info)
{
var str = "<tr>";
// You can get each value as info.name or info["name"].
// Let's get the first name using the first way.
str += "<td>" + info.fname + "</td>";
str += "<td>" + info["lname"] + "</td>";
str += "<td>" + info["dance"] + "</td>";
str += "<td>" + info["pie"] + "</td>";
str += "</tr>\n";
$("#info").html(str);
}
php代码跟上一个版本非常像,只不过这次返回的是JSON字符串
people3.php
$cmd = @$_REQUEST["cmd"];
$id = @$_REQUEST["id"];
mysql_connect($server, $user, $password);
mysql_select_db("test");
if ($cmd == "init")
{
$result = mysql_query("select id, fname, lname from people");
$user_array = array();
while($row = mysql_fetch_array($result, MYSQL_ASSOC))
$user_array[] = $row;
echo json_encode($user_array);
}
elseif ($cmd == "info")
{
$id = mysql_real_escape_string($id);
$result = mysql_query("select * from people where id='$id'");
$info = mysql_fetch_array($result, MYSQL_ASSOC);
echo json_encode($info);
}
?>
json在php5.2以后的版本中默认启用。如果是更早的版本,请参考manual section
相关文章
评论
共3 条评论 to “[译]将基于web的php程序迁移到ajax”
发表评论

你真是与时俱进啊!
这样的文章蛮有用的 谢谢
[回复此评论]
我晕,留言竟然说没写**...
再来一次
偶一直都用php+json.js实现无刷新效果,现在想结合php+json.js+Jquery不知道有没再带上json.js的必要.博主指一下,偶菜得可以`呵呵`
[回复此评论]
恩,我也觉得json挺方便的,可以参考一下我的另一篇文章:
http://www.live-my-life-with-yuyi.com/blog/?p=140
[回复此评论]