2006 年 9 月 07 日
2006 年最時(shí)髦的詞莫過于 Web 2.0。Web 2.0 究竟意味著什么,這是一個(gè)熱門的爭論話題,但它似乎與一種很酷的動(dòng)態(tài) Web 應(yīng)用程序有關(guān)。那些 Web 應(yīng)用程序 —— 通常以 PHP 開發(fā) —— 使用動(dòng)態(tài) HTML(DHTML)創(chuàng)建頁面,移動(dòng)及更改此頁面時(shí)無需返回服務(wù)器進(jìn)行更新。Jack Herrington 在 “使用 PHP 和 DHTML 設(shè)計(jì) Web 2.0 應(yīng)用程序” 系列文章中教您開始使用這項(xiàng)技術(shù)。
DHTML 是包含 JavaScript 代碼的 HTML,這些代碼可更改瀏覽器中的頁面布局,而無需返回服務(wù)器。在您編寫 HTML 頁面時(shí),您實(shí)際上是在編寫一個(gè)對象樹。所有標(biāo)記 —— 小小的 <table> 和 <p> —— 都成為 JavaScript 空間中的對象。使用 JavaScript,您可以更改其內(nèi)容、層疊樣式表(Cascading Style Sheets,CSS)的式樣以及位置 —— 均無需再返回服務(wù)器。DHTML 是 HTML、CSS 和 JavaScript 的交集。
自瀏覽器中添加了 JavaScript 代碼后,使用 DHTML 的技術(shù)就已出現(xiàn),但對此技術(shù)的支持一直參差不齊。早期,Microsoft? Internet Explorer 在這方面做得非常出色,但同一時(shí)期的 Netscape V4 缺乏支持。近來,Mozilla 和 Firefox 漸漸提供了可靠的 DHTML 支持。有些人認(rèn)為形勢已經(jīng)與過去完全不同,Internet Explorer 現(xiàn)已在這方面落后。
DHTML 的優(yōu)缺點(diǎn)
在您的頁面中結(jié)合 JavaScript 將使頁面具有動(dòng)態(tài)性,并且能夠帶來更出色的用戶體驗(yàn)。用戶可更快地獲得更多數(shù)據(jù)、從不同角度查看信息、無縫地在站點(diǎn)中導(dǎo)航 —— 而站點(diǎn)不必返回服務(wù)器處獲得大量頁面。
然而,也存在避免使用 JavaScript 的理由:瀏覽器兼容性。早期僅使用平面 HTML 時(shí),Internet Explorer 呈現(xiàn)頁面的方式與 Netscape 不同。那些問題已得到解決。但隨著 CSS 支持的添加,出現(xiàn)了新的兼容性問題。如今,多半 CSS 問題已被解決,但又出現(xiàn)了 JavaScript 兼容性問題。
這些兼容性問題沒有簡單的解決方案。您需要根據(jù)需要測試和支持的瀏覽器的數(shù)量來衡量 JavaScript 的收益。
這里我們給出幾條建議:
- 使 JavaScript 盡可能地簡單。
- 發(fā)現(xiàn)兼容性問題時(shí),首先上網(wǎng)查找最佳解決方法。您往往會(huì)找到經(jīng)過精心研究的答案。
- 擁有一個(gè)平面 HTML 代用系統(tǒng),以應(yīng)對您不支持的那些瀏覽器。
- 保留一份支持的瀏覽器列表(及其版本號(hào))。
- 在 Mac 和 Microsoft Windows? 中查看 Internet Explorer。
本文的示例盡可能保持簡單清楚。但僅在 Firefox 上進(jìn)行了測試,所以會(huì)出現(xiàn)一些兼容性問題。本文將在出現(xiàn)兼容性問題的地方提醒您,以便您獲得更多的實(shí)踐經(jīng)驗(yàn)。
實(shí)現(xiàn) DHTML 最簡便的方法就是首先在平面 HTML 頁面中編寫,不使用 PHP 或任何服務(wù)器端語言,隨后以該代碼作為 PHP 代碼模板來生成 DHTML。通過這種方式,您可檢查解決方案的基礎(chǔ),并將服務(wù)器的問題與客戶機(jī)的問題區(qū)分開來。在本文中,每個(gè)示例都首先給出 HTML,隨后再給出相應(yīng)的 PHP 代碼。
廣告框
第一個(gè)示例簡單且兼容:浮動(dòng)廣告框。圖 1 展示了一個(gè)帶有 Close 按鈕的對話框,浮動(dòng)于頁面之上。
圖 1. 浮動(dòng)廣告框
用戶可單擊 Close 按鈕關(guān)閉廣告框,如圖 2 所示。
圖 2. 關(guān)閉廣告框后的頁面效果
清單 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? What
are the odds? Just buy five hundred or more of our product and we
will give you a 1% discount on additional orders. Only the Department
of 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 of
our 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 屬性根據(jù)元素與頁面左上角的相對位置定位元素。
為使廣告框消失,您為 close 錨定標(biāo)記編寫了一些 JavaScript 代碼。這里并未使用 http 協(xié)議,而是使用 javascript 協(xié)議,并調(diào)用了 closead 函數(shù)。closead JavaScript 函數(shù)獲取 ad <div> 的對象引用,并改變 CSS 樣式 visibility ,從 visible 設(shè)置為 hidden ,這樣廣告框就消失了。
本例展示了一些 DHTML 基本原理。首先是 id 屬性的用法。為動(dòng)態(tài)引用一個(gè)項(xiàng)目,通過 id 屬性給予其一個(gè)惟一的 ID。在本例中,您為廣告框設(shè)置的 ID 為 ad 。隨后使用 document.getElementById 方法獲取廣告框的 <div> 對象。
本例還示范了可在錨定標(biāo)記中使用的 javascript 偽 URL。使用它,您可以在放置鏈接的任意位置調(diào)用 JavaScript。
這些技術(shù)兼容其他瀏覽器。所有現(xiàn)代瀏覽器均支持 JavaScript、CSS、絕對定位和在運(yùn)行時(shí)對 visibility 屬性這樣的動(dòng)態(tài)元素進(jìn)行設(shè)置。
PHP 中的廣告框
現(xiàn)在已經(jīng)有了廣告框的 DHTML 代碼,接下來讓我們看看如何在 PHP 中實(shí)現(xiàn)它(參見清單 2)。該廣告框的惟一可選項(xiàng)就是顯示與否。PHP 代碼通過一個(gè)函數(shù)調(diào)用寫出了廣告框,根據(jù)環(huán)境決定是否調(diào)用頁面。
清單 2. 廣告框的 PHP 代碼
<?php
function 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? What
are the odds? Just buy five hundred or more of our product and we
will 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 of
our 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 函數(shù)通過靈活的 title 字符串將廣告置于頁面之上。為獲得在多個(gè)頁面上發(fā)布廣告的能力,您可將此函數(shù)提取出來,放在一個(gè)單獨(dú)的文件中,這樣,每次需要在頁面上插入廣告時(shí),只需包含此獨(dú)立文件即可。
彈出框
浮動(dòng)對話框主題的另一變種就是彈出框。您可使用彈出框提供用戶請求的附加信息??紤]圖 3 所示文本。
圖 3. 關(guān)于動(dòng)物的純文本頁面
如果用戶能看到關(guān)于長頸鹿的更多信息,豈不是更好嗎?文本包含一個(gè)便捷的鏈接,如果您單擊此鏈接,將看到圖 4 所示的彈出框。
圖 4. 關(guān)于長頸鹿的更多信息
本例中,您應(yīng)請求提供了一個(gè)對話框,并依據(jù)文檔中的文本定位此對話框。代碼如清單 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 文字旁的錨定標(biāo)記將調(diào)用 JavaScript 來顯示彈出框。
popup JavaScript 方法使用 word ID 查找 giraffe 文本。隨后使用 offsetLeft 和 offsetTop 值使彈出框恰好位于文本之下。若彈出框已為可見狀態(tài),則隱藏它。
您可在顯示彈出框之前設(shè)置其內(nèi)容,只需設(shè)置 popup <div> 對象的 innerHTML 成員即可。
此代碼的兼容性相當(dāng)好。但依然可能會(huì)出現(xiàn)問題,這是因?yàn)槊總€(gè)瀏覽器的 offsetLeft 和 offsetTop 值可能有所不同,對于帶有復(fù)雜嵌套內(nèi)容的頁面而言更是如此。為在復(fù)雜頁面中獲得更準(zhǔn)確的位置讀數(shù),您可能需要遞歸增加 offsetLeft 和 offsetTop 值,為此,使用 offsetParent 對象在您沿 HTML 對象樹移動(dòng)時(shí)獲取各對象的父對象。
彈出框的 PHP 代碼
有了 DHTML 代碼后,即可更輕松地在 PHP 應(yīng)用程序中使用彈出框。清單 4 給出了 PHP 代碼。
清單 4. 彈出框的 PHP 代碼
<?php
function 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>
|
在本例中,您將標(biāo)題的生成與各彈出框的放置相分離。頁面必須調(diào)用 head 標(biāo)記中的 popup_header ,然后添加 id 值為 popup 的 <div> 標(biāo)記。隨后,只要需要彈出框,頁面就會(huì)調(diào)用 PHP 函數(shù) popup 。
PHP 函數(shù) popup 接受 3 個(gè)參數(shù):彈出框的 ID、純文本版本以及單擊項(xiàng)目時(shí)彈出的文本。函數(shù)隨后會(huì)呈現(xiàn)一個(gè)錨定標(biāo)記,其外觀幾乎與原 DHTML 中的版本完全相同。
由于一個(gè)頁面上可能會(huì)顯示多個(gè)彈出框,所以添加了第三個(gè)參數(shù)以提供彈出框中顯示的文本。為實(shí)現(xiàn)這一功能,為 JavaScript 函數(shù) popup 再添加一個(gè)參數(shù)。<div> 標(biāo)記的 innerHTML 隨后會(huì)設(shè)置為這個(gè)新參數(shù)的內(nèi)容。
微調(diào)控制項(xiàng)
在頁面中隱藏和顯示數(shù)據(jù)的另一選擇就是微調(diào)控制項(xiàng)(spinner)。在此模型中,頁面劃分為幾部分,各部分可使用微調(diào)控制項(xiàng)獨(dú)立隱藏或顯示。圖 5 展示了帶有兩部分微調(diào)控制項(xiàng)的頁面,各部分最初都是關(guān)閉的。
圖 5. 各微調(diào)控制項(xiàng)部分均關(guān)閉的頁面
單擊 Level One 部分中的 Open 鏈接將顯示此部分的內(nèi)容,如圖 6 所示。
圖 6. 展開了第一個(gè)微調(diào)控制項(xiàng)部分的頁面
您可以使用圖形來取代文字 open 和 closed。按照慣例,通常使用向右的三角形取代 closed,向下的三角形取代 open;也可使用加減號(hào),加號(hào)表示 closed,減號(hào)表示 open。(對于哪種方式更好的評價(jià)涉及到 Mac 與 Windows 對比的爭論。這兩個(gè)平臺(tái)上的微調(diào)控制項(xiàng)正與這兩種不同的方式分別對應(yīng)。)
清單 5 中的代碼展示了這些微調(diào)控制項(xiàng)的工作原理:
清單 5. 微調(diào)控制項(xiàng)的 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 = ‘a(chǎn)uto‘;
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> 定義了各部分及其內(nèi)容。按照慣例,為標(biāo)題賦予 ID lev 加上一個(gè)數(shù)字(例如,lev2 ),正文使用相同的 ID 加后綴 _body 。lev2 是微調(diào)控制項(xiàng)的鏈接,lev2_body 是該項(xiàng)目的正文。
微調(diào)控制項(xiàng)的智能部分是在 spin 函數(shù)中實(shí)現(xiàn)的,它查看微調(diào)控制項(xiàng)正文部分的可見性,并加以轉(zhuǎn)換,將可見轉(zhuǎn)變?yōu)殡[藏、隱藏轉(zhuǎn)變?yōu)榭梢姟?/p>
在項(xiàng)目不可見時(shí),將 height 屬性設(shè)置為 0px ,而在項(xiàng)目可見時(shí)將此屬性設(shè)置為 auto 。對于 Internet Explorer,項(xiàng)目不可見時(shí),其空間也會(huì)隨之折疊。但對于 Firefox,內(nèi)容不可見時(shí),其空間依然作為占位符存在。您需要將 height 設(shè)置為 0px ,才能使空間正確地折疊起來。
為使用圖形取代文本來表示展開和關(guān)閉狀態(tài),更改代碼,改變微調(diào)控制項(xiàng)對象的 innerHTML 值,使其指定一個(gè)圖像標(biāo)記而非文本。
微調(diào)控制項(xiàng)的 PHP 代碼
為在 PHP 中實(shí)現(xiàn)微調(diào)控制項(xiàng),采用服務(wù)器端創(chuàng)建 DHTML 代碼的標(biāo)準(zhǔn)模式即可,在 start 和 end 函數(shù)中劃分 HTML 的各部分。PHP 代碼如清單 6 所示。
清單 6. 微調(diào)控制項(xiàng)的 PHP 代碼
<?php
function 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 = ‘a(chǎn)uto‘;
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>
|
通過調(diào)用 start_spinner 和 end_spinner 劃分內(nèi)容的各部分。start_spinner 函數(shù)接受兩個(gè)參數(shù):微調(diào)控制項(xiàng)的 ID 及其標(biāo)題。end_spinner 調(diào)用結(jié)束 start_spinner 中打開的 <div> 標(biāo)記,以容納微調(diào)控制項(xiàng)的內(nèi)容。
您可將微調(diào)控制項(xiàng)的內(nèi)容作為第三個(gè)參數(shù)引入。但在一般情況下,這些內(nèi)容部分形式復(fù)雜,若您以這種方式編寫代碼,界面使用起來將非常困難。在 start 和 end 函數(shù)中劃分動(dòng)態(tài)部分的模式意味著您可以隨意選擇其中 PHP 的復(fù)雜度。
選項(xiàng)卡
選項(xiàng)卡是查看內(nèi)容不同部分的另一種常見方法。在 MetaCritic 站點(diǎn)上可以看到選項(xiàng)卡的輕量級(jí)版本(參見 參考資料),該站點(diǎn)使用選項(xiàng)卡切換游戲列表的查看方式 —— 按名稱查看或按評價(jià)分?jǐn)?shù)查看,而且不必返回服務(wù)器。圖 7 展示了此游戲列表的簡化示例。
圖 7. 按名稱排列的游戲
若要查看按評價(jià)分?jǐn)?shù)排列的游戲,單擊 By Score 鏈接。列表會(huì)發(fā)生變化,如圖 8 所示。
圖 8. 按分?jǐn)?shù)排列的游戲
MetaCritic 站點(diǎn)沒有在客戶端進(jìn)行復(fù)雜的排序,而是使用了相當(dāng)于 flash 卡的一種方式:一個(gè)選項(xiàng)卡上的列表按名稱排列,另外一個(gè)選項(xiàng)卡按分?jǐn)?shù)排列。單擊鏈接時(shí),則隱藏一個(gè)選項(xiàng)卡,顯示另外一個(gè)選項(xiàng)卡。代碼如清單 7 所示。
清單 7. 選項(xiàng)卡的 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>
|
兩個(gè)列表分別位于兩個(gè) <div> 標(biāo)記中:names 和 score 。names <div> 擁有按名稱排序的游戲列表,score 擁有按分?jǐn)?shù)排序的列表。show 函數(shù)連接到 By Name 和 By Score 鏈接,首先使所有列表均不可見,隨后使所選列表可見。
還有其他一些有趣的東西。首先,您使用 className 屬性動(dòng)態(tài)地更改了鏈接的 CSS 類。這也就是所選按鈕從白色變?yōu)楹谏脑颉?/p>
其次,觀察 names 和 score 的 CSS。兩個(gè) <div> 均按絕對位置定位于左上部,但不在頁面的左上角。這是因?yàn)樗鼈兾挥?ID 值為 container 的 <div> 中,而 container 的位置設(shè)置為 relative 。container <div> 有效地重置了包含于其中的項(xiàng)目的原點(diǎn)。表格是相對于容器而不是頁面來定位的。
這種 DHTML 不但復(fù)雜度合理、有趣,而且?guī)缀跖c所有現(xiàn)代瀏覽器兼容。
選項(xiàng)卡的 PHP 代碼
在 PHP 中開發(fā) DHTML 的另外一種工具就是輸出緩存區(qū) 的使用。輸出緩存區(qū)存儲(chǔ)頁面中的文本、選項(xiàng)卡和重復(fù)素材,并將其作為字符串返回,供以后使用。為實(shí)現(xiàn)選項(xiàng)卡,將使用輸出緩存區(qū),在把選項(xiàng)卡內(nèi)容呈現(xiàn)到頁面中之前將其作為字符串存儲(chǔ)(參見清單 8)。
清單 8. 選項(xiàng)卡的 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 代碼首先定義了兩個(gè)變量:tabs 和 current_tab 。tabs 數(shù)組保存各選項(xiàng)卡的 id 、title 和 html 值。current_tab 指向 start_tab 和 end_tab 調(diào)用間創(chuàng)建的選項(xiàng)卡。start_tab 函數(shù)接受兩個(gè)參數(shù):選項(xiàng)卡的 id 值和 title 值。它隨后會(huì)啟動(dòng)輸出緩存。
end_tab 函數(shù)終止輸出緩存,并將作為結(jié)果的 HTML 存儲(chǔ)在 tabs 數(shù)組的 current_tab 的 html 值中。
再往下看,可以看到 start_tab 和 end_tab 調(diào)用中包含要在選項(xiàng)卡中呈現(xiàn)的選項(xiàng)卡內(nèi)容。
將選項(xiàng)卡呈現(xiàn)在頁面上的重要函數(shù)就是 place_tab_buttons 和 place_tab_content 。place_tab_buttons 函數(shù)創(chuàng)建有著選項(xiàng)卡名稱的錨定標(biāo)記,單擊錨定標(biāo)記時(shí),將切換選項(xiàng)卡。place_tab_content 函數(shù)創(chuàng)建具有輸出緩存區(qū)存儲(chǔ)的各選項(xiàng)卡內(nèi)容的 <div> 標(biāo)記。
get_tab_ids 和 get_first_tab 是創(chuàng)建 JavaScript 的輔助函數(shù)。它們分別返回選項(xiàng)卡 ID 的完整列表和第一個(gè)選項(xiàng)卡的 ID。
下期預(yù)告
“使用 PHP 和 DHTML 設(shè)計(jì) Web 2.0 應(yīng)用程序” 系列的下一篇文章將介紹通過 JavaScript 生成動(dòng)態(tài)圖片的內(nèi)容。下篇文章將教您如何動(dòng)態(tài)創(chuàng)建新的 HTML 元素,并在 PHP 應(yīng)用程序所顯示的頁面中定位這些元素。
參考資料
學(xué)習(xí)
獲得產(chǎn)品和技術(shù)
- 使用 IBM 試用軟件 革新您的下一個(gè)開放源碼開發(fā)項(xiàng)目,可通過下載獲得,也可通過 DVD 獲得。
討論
關(guān)于作者
 |
|
 |
Jack D. Herrington 是一名高級(jí)軟件工程師,有著二十余年的經(jīng)驗(yàn)。他撰寫了三本圖書:Code Generation in Action、Podcasting Hacks 和即將出版的 PHP Hacks。他的作品還包括三十多篇文章。
|
|