| 级别: 中级 Jack Herrington (jack_d_herrington@codegeneration.net), 高级软件工程师, "Code Generation Network"
2006 年 9 月 07 日 2006 年最时髦的词莫过于 Web 2.0。Web 2.0 究竟意味着什么,这是一个热门的争论话题,但它似乎与一种很酷的动态 Web 应用程序有关。那些 Web 应用程序 —— 通常以 PHP 开发 —— 使用动态 HTML(DHTML)创建页面,移动及更改此页面时无需返回服务器进行更新。Jack Herrington 在 “使用 PHP 和 DHTML 设计 Web 2.0 应用程序” 系列文章中教您开始使用这项技术。 DHTML 是包含 JavaScript 代码的 HTML,这些代码可更改浏览器中的页面布局,而无需返回服务器。在您编写 HTML 页面时,您实际上是在编写一个对象树。所有标记 —— 小小的 <table> 和 <p> —— 都成为 JavaScript 空间中的对象。使用 JavaScript,您可以更改其内容、层叠样式表(Cascading Style Sheets,CSS)的式样以及位置 —— 均无需再返回服务器。DHTML 是 HTML、CSS 和 JavaScript 的交集。 自浏览器中添加了 JavaScript 代码后,使用 DHTML 的技术就已出现,但对此技术的支持一直参差不齐。早期,Microsoft® Internet Explorer 在这方面做得非常出色,但同一时期的 Netscape V4 缺乏支持。近来,Mozilla 和 Firefox 渐渐提供了可靠的 DHTML 支持。有些人认为形势已经与过去完全不同,Internet Explorer 现已在这方面落后。 DHTML 的优缺点 在您的页面中结合 JavaScript 将使页面具有动态性,并且能够带来更出色的用户体验。用户可更快地获得更多数据、从不同角度查看信息、无缝地在站点中导航 —— 而站点不必返回服务器处获得大量页面。 然而,也存在避免使用 JavaScript 的理由:浏览器兼容性。早期仅使用平面 HTML 时,Internet Explorer 呈现页面的方式与 Netscape 不同。那些问题已得到解决。但随着 CSS 支持的添加,出现了新的兼容性问题。如今,多半 CSS 问题已被解决,但又出现了 JavaScript 兼容性问题。 这些兼容性问题没有简单的解决方案。您需要根据需要测试和支持的浏览器的数量来衡量 JavaScript 的收益。 这里我们给出几条建议: - 使 JavaScript 尽可能地简单。
- 发现兼容性问题时,首先上网查找最佳解决方法。您往往会找到经过精心研究的答案。
- 拥有一个平面 HTML 代用系统,以应对您不支持的那些浏览器。
- 保留一份支持的浏览器列表(及其版本号)。
- 在 Mac 和 Microsoft Windows® 中查看 Internet Explorer。
本文的示例尽可能保持简单清楚。但仅在 Firefox 上进行了测试,所以会出现一些兼容性问题。本文将在出现兼容性问题的地方提醒您,以便您获得更多的实践经验。 实现 DHTML 最简便的方法就是首先在平面 HTML 页面中编写,不使用 PHP 或任何服务器端语言,随后以该代码作为 PHP 代码模板来生成 DHTML。通过这种方式,您可检查解决方案的基础,并将服务器的问题与客户机的问题区分开来。在本文中,每个示例都首先给出 HTML,随后再给出相应的 PHP 代码。
广告框 第一个示例简单且兼容:浮动广告框。图 1 展示了一个带有 Close 按钮的对话框,浮动于页面之上。 图 1. 浮动广告框
用户可单击 Close 按钮关闭广告框,如图 2 所示。 图 2. 关闭广告框后的页面效果
清单 1 为页面代码。 清单 1. 广告框代码 <html><head><title>Ad box demonstration</title><style>body { width: 800px;}.ad-box { background: #eee; border: 1px solid black; padding: 5px; position: absolute; left: 50px; top: 50px; width: 600px;}.ad-box-title { background: #ccc; padding: 5px; font-weight: bold; font-size: large; text-align: center; text-transform: uppercase; letter-spacing: 0.2em;}</style><script>function closead(){ var obj = document.getElementById( "ad" ); obj.style.visibility = "hidden";}</script></head><body><div class="ad-box" id="ad"><div class="ad-box-title">Special offer</div><p>You have been selected for our special offer. Can you imagine? Whatare the odds? Just buy five hundred or more of our product and wewill give you a 1% discount on additional orders. Only the Departmentof Defense gets deals like that!</p><p style="text-align: right;"><a href="javascript:closead();">close</a></p></div><p>This is our home page. Welcome to it. Here we talk about all ofour great products.</p><h1>Products</h1><p>This is a list of our products:</p><ul><li>The amazing all in one toothpix holder and axe grinder.</li><li>The complete Jean Claude Van Damme DVD collection.</li></ul></body></html> | 本例的大部分工作是使用 CSS 完成的。使用 position CSS 属性,使广告框浮在页面文本之上。left 和 top 属性根据元素与页面左上角的相对位置定位元素。 为使广告框消失,您为 close 锚定标记编写了一些 JavaScript 代码。这里并未使用 http 协议,而是使用 javascript 协议,并调用了 closead 函数。closead JavaScript 函数获取 ad <div> 的对象引用,并改变 CSS 样式 visibility,从 visible 设置为 hidden,这样广告框就消失了。 本例展示了一些 DHTML 基本原理。首先是 id 属性的用法。为动态引用一个项目,通过 id 属性给予其一个惟一的 ID。在本例中,您为广告框设置的 ID 为 ad。随后使用 document.getElementById 方法获取广告框的 <div> 对象。 本例还示范了可在锚定标记中使用的 javascript 伪 URL。使用它,您可以在放置链接的任意位置调用 JavaScript。 这些技术兼容其他浏览器。所有现代浏览器均支持 JavaScript、CSS、绝对定位和在运行时对 visibility 属性这样的动态元素进行设置。
PHP 中的广告框 现在已经有了广告框的 DHTML 代码,接下来让我们看看如何在 PHP 中实现它(参见清单 2)。该广告框的惟一可选项就是显示与否。PHP 代码通过一个函数调用写出了广告框,根据环境决定是否调用页面。 清单 2. 广告框的 PHP 代码 <?phpfunction place_ad( $title ){?><div class="ad-box" id="ad"><div class="ad-box-title"><?php echo( $title ); ?></div><p>You have been selected for our special offer. Can you imagine? Whatare the odds? Just buy five hundred or more of our product and wewill give you a 1% discount on additional orders. Only the Dept.of Defense gets deals like that!</p><p style="text-align: right;"><a href="javascript:closead();">close</a></p></div><?php}?><html><head><title>Ad box demonstration</title><style>body { width: 800px;}.ad-box { background: #eee; border: 1px solid black; padding: 5px; position: absolute; left: 50px; top: 50px; width: 600px;}.ad-box-title { background: #ccc; padding: 5px; font-weight: bold; font-size: large; text-align: center; text-transform: uppercase; letter-spacing: 0.2em;}</style><script>function closead(){ var obj = document.getElementById( "ad" ); obj.style.visibility = "hidden";}</script></head><body><?php place_ad( "Today's Special Offer!" ); ?><p>This is our home page. Welcome to it. Here we talk about all ofour great products.</p><h1>Products</h1><p>This is a list of our products:</p><ul><li>The amazing all in one toothpix holder and axe grinder.</li><li>The complete Jean Claude Van Damme DVD collection.</li></ul></body></html> | 全新的 place_ad PHP 函数通过灵活的 title 字符串将广告置于页面之上。为获得在多个页面上发布广告的能力,您可将此函数提取出来,放在一个单独的文件中,这样,每次需要在页面上插入广告时,只需包含此独立文件即可。
弹出框 浮动对话框主题的另一变种就是弹出框。您可使用弹出框提供用户请求的附加信息。考虑图 3 所示文本。 图 3. 关于动物的纯文本页面
如果用户能看到关于长颈鹿的更多信息,岂不是更好吗?文本包含一个便捷的链接,如果您单击此链接,将看到图 4 所示的弹出框。 图 4. 关于长颈鹿的更多信息
本例中,您应请求提供了一个对话框,并依据文档中的文本定位此对话框。代码如清单 3 所示。 清单 3. 弹出框的 HTML 代码 <html><head><title>Pop up Example</title><style type="text/css">body { font-family: arial, verdana, sans serif; }#popup { position: absolute; padding: 5px; border: 1px solid black; background: #eee; left: 0px; top: 0px; visibility: hidden;}</style><script>function popup( id ){ var obj = document.getElementById( id ); var popup = document.getElementById( 'popup' ); if ( popup.style.visibility == 'visible' ) { popup.style.visibility = 'hidden'; } else { popup.style.left = obj.offsetLeft + "px"; popup.style.top = ( obj.offsetTop + 20 ) + "px"; popup.style.visibility = 'visible'; }}</script></head><body><div id="popup">An animal with a very long neck.</div><h2>Animals</h2>A <a href="javascript:popup('word')" id="word">giraffe</a>is a very interesting animal.</body></html> | 本例中,包含弹出信息的 popup <div> 最初定义为 hidden,绝对位置为页面左上角。随后 giraffe 文字旁的锚定标记将调用 JavaScript 来显示弹出框。 popup JavaScript 方法使用 word ID 查找 giraffe 文本。随后使用 offsetLeft 和 offsetTop 值使弹出框恰好位于文本之下。若弹出框已为可见状态,则隐藏它。 您可在显示弹出框之前设置其内容,只需设置 popup <div> 对象的 innerHTML 成员即可。 此代码的兼容性相当好。但依然可能会出现问题,这是因为每个浏览器的 offsetLeft 和 offsetTop 值可能有所不同,对于带有复杂嵌套内容的页面而言更是如此。为在复杂页面中获得更准确的位置读数,您可能需要递归增加 offsetLeft 和 offsetTop 值,为此,使用 offsetParent 对象在您沿 HTML 对象树移动时获取各对象的父对象。
弹出框的 PHP 代码 有了 DHTML 代码后,即可更轻松地在 PHP 应用程序中使用弹出框。清单 4 给出了 PHP 代码。 清单 4. 弹出框的 PHP 代码 <?phpfunction popup_header(){?><style type="text/css">body { font-family: arial, verdana, sans serif; }#popup { position: absolute; padding: 5px; border: 1px solid black; background: #eee; left: 0px; top: 0px; visibility: hidden;}</style><script>function popup( id, info ){ var obj = document.getElementById( id ); var popup = document.getElementById( 'popup' ); if ( popup.style.visibility == 'visible' ) { popup.style.visibility = 'hidden'; } else { popup.innerHTML = info; popup.style.left = obj.offsetLeft + "px"; popup.style.top = ( obj.offsetTop + 20 ) + "px"; popup.style.visibility = 'visible'; }}</script><?php}function popup( $id, $text, $info ){?><a href="javascript:popup('<?php echo($id) ?>','<?php echo($info) ?>')" id="<?php echo($id) ?>"><?php echo($text) ?></a><?php}?><html><head><title>Pop up Example</title><?php popup_header(); ?></head><body><div id="popup"></div><h2>Animals</h2>A<?php popup( 'word', 'giraffe', 'An animal with a very long neck.' ) ?>is a very interesting animal.</body></html>?tml> | 在本例中,您将标题的生成与各弹出框的放置相分离。页面必须调用 head 标记中的 popup_header,然后添加 id 值为 popup 的 <div> 标记。随后,只要需要弹出框,页面就会调用 PHP 函数 popup。 PHP 函数 popup 接受 3 个参数:弹出框的 ID、纯文本版本以及单击项目时弹出的文本。函数随后会呈现一个锚定标记,其外观几乎与原 DHTML 中的版本完全相同。 由于一个页面上可能会显示多个弹出框,所以添加了第三个参数以提供弹出框中显示的文本。为实现这一功能,为 JavaScript 函数 popup 再添加一个参数。<div> 标记的 innerHTML 随后会设置为这个新参数的内容。
微调控制项 在页面中隐藏和显示数据的另一选择就是微调控制项(spinner)。在此模型中,页面划分为几部分,各部分可使用微调控制项独立隐藏或显示。图 5 展示了带有两部分微调控制项的页面,各部分最初都是关闭的。 图 5. 各微调控制项部分均关闭的页面
单击 Level One 部分中的 Open 链接将显示此部分的内容,如图 6 所示。 图 6. 展开了第一个微调控制项部分的页面
您可以使用图形来取代文字 open 和 closed。按照惯例,通常使用向右的三角形取代 closed,向下的三角形取代 open;也可使用加减号,加号表示 closed,减号表示 open。(对于哪种方式更好的评价涉及到 Mac 与 Windows 对比的争论。这两个平台上的微调控制项正与这两种不同的方式分别对应。) 清单 5 中的代码展示了这些微调控制项的工作原理: 清单 5. 微调控制项的 HTML 代码 <html><head><title>Spinner Example</title><style type="text/css">body { font-family: arial, verdana, sans serif; width: 800px; }.item-header a { font-size: small; }.item-header { font-weight: bold; border-bottom: 1px solid black; font-size: x-large;}.item-body { margin: 0px; font-size: small; visibility: hidden; height: 0px;}</style><script>function spin( obj ){ var spinner = document.getElementById( obj ); var spinner_content = document.getElementById( obj+"_body" ); if ( spinner_content.style.visibility == 'visible' ) { spinner.innerHTML = 'open'; spinner_content.style.visibility = 'hidden'; spinner_content.style.height = '0px'; spinner_content.style.margin = '0px'; } else { spinner.innerHTML = 'close'; spinner_content.style.visibility = 'visible'; spinner_content.style.height = 'auto'; spinner_content.style.margin = '20px 0px 20px 50px'; }}</script></head><body><div class="item-header"><a href="javascript:spin('lev1')" id="lev1">open</a> Level One</div><div class="item-body" id="lev1_body">This is the content of level one.</div><div class="item-header"><a href="javascript:spin('lev2')" id="lev2">open</a> Level Two</div><div class="item-body" id="lev2_body">This is the content of level two.</div></body></html> | 两组 <div> 定义了各部分及其内容。按照惯例,为标题赋予 ID lev 加上一个数字(例如,lev2),正文使用相同的 ID 加后缀 _body。lev2 是微调控制项的链接,lev2_body 是该项目的正文。 微调控制项的智能部分是在 spin 函数中实现的,它查看微调控制项正文部分的可见性,并加以转换,将可见转变为隐藏、隐藏转变为可见。 在项目不可见时,将 height 属性设置为 0px,而在项目可见时将此属性设置为 auto。对于 Internet Explorer,项目不可见时,其空间也会随之折叠。但对于 Firefox,内容不可见时,其空间依然作为占位符存在。您需要将 height 设置为 0px,才能使空间正确地折叠起来。 为使用图形取代文本来表示展开和关闭状态,更改代码,改变微调控制项对象的 innerHTML 值,使其指定一个图像标记而非文本。
微调控制项的 PHP 代码 为在 PHP 中实现微调控制项,采用服务器端创建 DHTML 代码的标准模式即可,在 start 和 end 函数中划分 HTML 的各部分。PHP 代码如清单 6 所示。 清单 6. 微调控制项的 PHP 代码 <?phpfunction start_spinner( $id, $title ){?><div class="item-header"><a href="javascript:spin('<?php echo( $id ); ?>')" id="<?php echo( $id ); ?>">open</a> <?php echo( $title ); ?></div><div class="item-body" id="<?php echo( $id ); ?>_body"><?php}function end_spinner(){?></div><?php}?><html><head><title>Spinner Example</title><style type="text/css">body { font-family: arial, verdana, sans serif; width: 800px; }.item-header a { font-size: small; }.item-header { font-weight: bold; border-bottom: 1px solid black; font-size: x-large;}.item-body { margin: 0px; font-size: small; visibility: hidden; height: 0px;}</style><script>function spin( obj ){ var spinner = document.getElementById( obj ); var spinner_content = document.getElementById( obj+"_body" ); if ( spinner_content.style.visibility == 'visible' ) { spinner.innerHTML = 'open'; spinner_content.style.visibility = 'hidden'; spinner_content.style.height = '0px'; spinner_content.style.margin = '0px'; } else { spinner.innerHTML = 'close'; spinner_content.style.visibility = 'visible'; spinner_content.style.height = 'auto'; spinner_content.style.margin = '20px 0px 20px 50px'; }}</script></head><body><?php start_spinner( 'lev1', "Level One" ); ?>This is the content of level one.<?php end_spinner( ); ?><?php start_spinner( 'lev2', "Level Two" ); ?>This is the content of level two.<?php end_spinner( ); ?></body></html> | 通过调用 start_spinner 和 end_spinner 划分内容的各部分。start_spinner 函数接受两个参数:微调控制项的 ID 及其标题。end_spinner 调用结束 start_spinner 中打开的 <div> 标记,以容纳微调控制项的内容。 您可将微调控制项的内容作为第三个参数引入。但在一般情况下,这些内容部分形式复杂,若您以这种方式编写代码,界面使用起来将非常困难。在 start 和 end 函数中划分动态部分的模式意味着您可以随意选择其中 PHP 的复杂度。
选项卡 选项卡是查看内容不同部分的另一种常见方法。在 MetaCritic 站点上可以看到选项卡的轻量级版本(参见 参考资料),该站点使用选项卡切换游戏列表的查看方式 —— 按名称查看或按评价分数查看,而且不必返回服务器。图 7 展示了此游戏列表的简化示例。 图 7. 按名称排列的游戏
若要查看按评价分数排列的游戏,单击 By Score 链接。列表会发生变化,如图 8 所示。 图 8. 按分数排列的游戏
MetaCritic 站点没有在客户端进行复杂的排序,而是使用了相当于 flash 卡的一种方式:一个选项卡上的列表按名称排列,另外一个选项卡按分数排列。单击链接时,则隐藏一个选项卡,显示另外一个选项卡。代码如清单 7 所示。 清单 7. 选项卡的 HTML 代码 <html><head><title>Tabs Example</title><style type="text/css">body { font-family: arial,verdana,sans serif; }.button-on, .button-off { padding: 3px; border: 1px solid black; }.button-on { background: #333; color: white; font-weight: bold; }.game-list { position: absolute; top: 0px; left: 0px; }.container { padding: 5px; border: 1px solid black; margin: 5px; position: relative; height: 400px; width: 200px; }</style><script>function show( divid ){ var tos = [ "names", "score" ]; for( var t in tos ) { var to = document.getElementById( tos[t] ); to.style.visibility = "hidden"; to.style.height = "0px"; var bo = document.getElementById( tos[t]+"-button" ); bo.className = "button-off" } var to = document.getElementById( divid ); to.style.visibility = "visible"; to.style.height = "auto"; var bo = document.getElementById( divid + "-button" ); bo.className = "button-on";}</script></head><body onload="show('names')">Sort by:<a href="javascript:show('names')" id="names-button" class="button-on">By Name</a><a href="javascript:show('score')" id="score-button" class="button-off">By Score</a><br/><div class="container"><div id="names" class="game-list"><table width="100%"><tr><td>Crank Shaft</td><td>22</td></tr><tr><td>Driver</td><td>42</td></tr><tr><td>Football 2006</td><td>72</td></tr><tr><td>Soccer 2006</td><td>99</td></tr><tr><td>Xevious</td><td>32</td></tr></table></div><div id="score" class="game-list"><table width="100%"><tr><td>Crank Shaft</td><td>22</td></tr><tr><td>Xevious</td><td>32</td></tr><tr><td>Driver</td><td>42</td></tr><tr><td>Football 2006</td><td>72</td></tr><tr><td>Soccer 2006</td><td>99</td></tr></table></div></div></body></html> | 两个列表分别位于两个 <div> 标记中:names 和 score。names <div> 拥有按名称排序的游戏列表,score 拥有按分数排序的列表。show 函数连接到 By Name 和 By Score 链接,首先使所有列表均不可见,随后使所选列表可见。 还有其他一些有趣的东西。首先,您使用 className 属性动态地更改了链接的 CSS 类。这也就是所选按钮从白色变为黑色的原因。 其次,观察 names 和 score 的 CSS。两个 <div> 均按绝对位置定位于左上部,但不在页面的左上角。这是因为它们位于 ID 值为 container 的 <div> 中,而 container 的位置设置为 relative。container <div> 有效地重置了包含于其中的项目的原点。表格是相对于容器而不是页面来定位的。 这种 DHTML 不但复杂度合理、有趣,而且几乎与所有现代浏览器兼容。
选项卡的 PHP 代码 在 PHP 中开发 DHTML 的另外一种工具就是输出缓存区 的使用。输出缓存区存储页面中的文本、选项卡和重复素材,并将其作为字符串返回,供以后使用。为实现选项卡,将使用输出缓存区,在把选项卡内容呈现到页面中之前将其作为字符串存储(参见清单 8)。 清单 8. 选项卡的 PHP 代码 <?php$tabs = array();$current_tab = null;function start_tab( $id, $title ){ global $tabs, $current_tab; ob_start(); $current_tab = $id; $tabs[ $id ] = array( 'title' => $title, 'html' => "" );}function end_tab(){ global $tabs, $current_tab; $tabs[ $current_tab ][ 'html' ] = ob_get_contents(); ob_end_clean();}function get_tab_ids(){ global $tabs; $ids = array(); foreach( $tabs as $tabid => $tab ) { $ids []= "'".$tabid."'"; } return $ids;}function get_first_tab(){ $tabs = get_tab_ids(); return $tabs[0];}function place_tab_buttons(){ global $tabs; foreach( $tabs as $tabid => $tab ) {?><a href="javascript:show('<?php echo($tabid); ?>')" id="<?php echo($tabid); ?>-button" class="button-off"><?php echo( $tab['title'] ); ?></a><?php }}function place_tab_content(){ global $tabs; foreach( $tabs as $tabid => $tab ) {?><div id="<?php echo($tabid); ?>" class="game-list"><?php echo( $tab['html'] ); ?></div><?php }}?><?php start_tab( 'names', "By Name" ); ?><table width="100%"><tr><td>Crank Shaft</td><td>22</td></tr><tr><td>Driver</td><td>42</td></tr><tr><td>Football 2006</td><td>72</td></tr><tr><td>Soccer 2006</td><td>99</td></tr><tr><td>Xevious</td><td>32</td></tr></table><?php end_tab( ); ?><?php start_tab( 'scores', "By Score" ); ?><table width="100%"><tr><td>Crank Shaft</td><td>22</td></tr><tr><td>Xevious</td><td>32</td></tr><tr><td>Driver</td><td>42</td></tr><tr><td>Football 2006</td><td>72</td></tr><tr><td>Soccer 2006</td><td>99</td></tr></table><?php end_tab( ); ?><html><head><title>Tabs Example</title><style type="text/css">body { font-family: arial,verdana,sans serif; }.button-on, .button-off { padding: 3px; border: 1px solid black; }.button-on { background: #333; color: white; font-weight: bold; }.game-list { position: absolute; top: 0px; left: 0px; }.container { padding: 5px; border: 1px solid black; margin: 5px; position: relative; height: 400px; width: 200px; }</style><script>function show( divid ){ var tos = [ <?php echo( join( ",", get_tab_ids() ) ); ?> ]; for( var t in tos ) { var to = document.getElementById( tos[t] ); to.style.visibility = "hidden"; to.style.height = "0px"; var bo = document.getElementById( tos[t]+"-button" ); bo.className = "button-off" } var to = document.getElementById( divid ); to.style.visibility = "visible"; to.style.height = "auto"; var bo = document.getElementById( divid + "-button" ); bo.className = "button-on";}</script></head><body onload="show(<?php echo( get_first_tab() ); ?>)">Sort by:<?php place_tab_buttons() ?><div class="container"><?php place_tab_content() ?></div></body></html> | PHP 代码首先定义了两个变量:tabs 和 current_tab。tabs 数组保存各选项卡的 id、title 和 html 值。current_tab 指向 start_tab 和 end_tab 调用间创建的选项卡。start_tab 函数接受两个参数:选项卡的 id 值和 title 值。它随后会启动输出缓存。 end_tab 函数终止输出缓存,并将作为结果的 HTML 存储在 tabs 数组的 current_tab 的 html 值中。 再往下看,可以看到 start_tab 和 end_tab 调用中包含要在选项卡中呈现的选项卡内容。 将选项卡呈现在页面上的重要函数就是 place_tab_buttons 和 place_tab_content。place_tab_buttons 函数创建有着选项卡名称的锚定标记,单击锚定标记时,将切换选项卡。place_tab_content 函数创建具有输出缓存区存储的各选项卡内容的 <div> 标记。 get_tab_ids 和 get_first_tab 是创建 JavaScript 的辅助函数。它们分别返回选项卡 ID 的完整列表和第一个选项卡的 ID。
下期预告 “使用 PHP 和 DHTML 设计 Web 2.0 应用程序” 系列的下一篇文章将介绍通过 JavaScript 生成动态图片的内容。下篇文章将教您如何动态创建新的 HTML 元素,并在 PHP 应用程序所显示的页面中定位这些元素。
参考资料 学习 获得产品和技术 - 使用 IBM 试用软件 革新您的下一个开放源码开发项目,可通过下载获得,也可通过 DVD 获得。
讨论
关于作者  | | |  | Jack D. Herrington 是一名高级软件工程师,有着二十余年的经验。他撰写了三本图书:Code Generation in Action、Podcasting Hacks 和即将出版的 PHP Hacks。他的作品还包括三十多篇文章。 | |