Jack Herrington (jack_d_herrington@codegeneration.net), 高級(jí)軟件工程師, "Code Generation Network"
2006 年 9 月 07 日
“使用 PHP 和 DHTML 設(shè)計(jì) Web 2.0 應(yīng)用程序” 系列文章的第 1 部分探討了如何使用 JavaScript、層疊樣式表(CSS) 和 HTML 構(gòu)建帶有選項(xiàng)卡、微調(diào)控制項(xiàng)、彈出框等用戶界面元素的 PHP 應(yīng)用程序。第 2 部分將擴(kuò)展上一篇文章的內(nèi)容,將圖形技術(shù)包含在內(nèi),使用 JavaScript 動(dòng)態(tài)創(chuàng)建新的 HTML 元素。
第 1 部分 介紹了移動(dòng)、隱藏和顯示 Web 頁(yè)面內(nèi)容的方法。但如何動(dòng)態(tài)創(chuàng)建新的 HTML 元素呢?該如何圖形化數(shù)據(jù)及使用類似的有趣技術(shù)呢?圖 1 展示了全世界文盲率的圖表(數(shù)據(jù)來自 Unesco,請(qǐng)參閱 參考資料)。
圖 1. 按年份排列的全球文盲率
這并非最有趣的數(shù)據(jù)集,但振奮人心。那么如果只想查看歐洲的文盲率呢?非常簡(jiǎn)單:?jiǎn)螕粝吕藛?,選擇 Europe 即可。
圖 2. 按年份排列的歐洲文盲率
圖表顯示出,歐洲的文盲率遠(yuǎn)遠(yuǎn)低于全球水平。清單 1 給出了產(chǎn)生此動(dòng)態(tài)圖表的代碼。
清單 1. 條形圖代碼
<html>
<head>
<title>Bar Graph Example</title>
<script>
var years = [ 1970, 1980, 1990, 1995, 2000, 2005, 2010, 2015 ];
var rates = [];
rates[ ‘World‘ ] = [ 36.6, 30.3, 24.7, 22.4,
20.3, 18.3, 16.5, 15.0 ];
rates[ ‘Africa‘ ] = [ 72.4, 62.4, 51.2, 45.6,
40.2, 35.2, 30.8, 26.8 ];
rates[ ‘America‘ ] = [ 14.8, 11.6, 9.0, 7.9,
6.9, 6.0, 5.3, 4.6 ];
rates[ ‘Asia‘ ] = [ 48.5, 38.7, 30.2, 27.2,
24.4, 21.8, 19.6, 17.7 ];
rates[ ‘Europe‘ ] = [ 6.4, 4.3, 2.8, 2.2, 1.8,
1.4, 1.1, 0.8 ];
rates[ ‘Oceania‘ ] = [ 11.1, 8.7, 7.1, 6.6,
6.1, 5.6, 5.3, 5.0 ];
function plot( region )
{
var html = "";
html += "<table width=‘100%‘ cellspacing=‘0‘ cellpadding=‘1‘>";
for( var year in years )
{
var val = Math.round( rates[region][year] );
html += "<tr>";
html += "<td width=‘8%‘>"+years[year]+"</td>";
html += "<td width=‘1%‘ class=‘bar-start‘></td>";
html += "<td width=‘92%‘>";
html += "<table width=‘100%‘ cellspacing=‘0‘ ";
html += "cellpadding=‘0‘><tr>";
html += "<td width=‘"+val+"%‘ class=‘bar-on‘>";
html += " </td>";
html += "<td width=‘"+(100-val);
html += "%‘ class=‘bar-off‘> </td>";
html += "</tr></table></td>";
html += "<td width=‘1%‘ class=‘bar-start‘></td>";
html += "</tr>";
}
html += "</table>";
document.getElementById( "graph" ).innerHTML = html;
}
</script>
<style>
body { font-family: arial, verdana, sans serif; }
.bar-on { background: blue; }
.bar-off { background: white; }
.bar-start { width:1px; background: black; }
#graph { width: 600px; }
</style>
</head>
<body onload="plot(‘World‘)">
Region:
<select onchange="plot(this.options[this.selectedIndex].value)">
<option value="World">World</option>
<option value="Africa">Africa</option>
<option value="America">America</option>
<option value="Asia">Asia</option>
<option value="Europe">Europe</option>
<option value="Oceania">Oceania</option>
</select><br/><br/>
Rates of illiteracy (larger is worse):<br/><br/>
<div id="graph">
</div>
</body>
</html>
|
首先給出了一個(gè) ID 為 "graph" 的空 <div> 。<body> 標(biāo)記的 onload 屬性告訴瀏覽器在載入頁(yè)面時(shí)調(diào)用 plot 函數(shù)。這段代碼有趣的地方就在于 plot 函數(shù)。
此函數(shù)首先創(chuàng)建了一個(gè)空字符串。接下來,它通過在字符串中添加 <table> 、<tr> 和 <td> 標(biāo)記構(gòu)建圖表。此函數(shù)隨后將 graph <div> 標(biāo)記的 innerHTML 屬性設(shè)置為新生成的 HTML。
圖形本身是一個(gè)表,有四列:年份、小分隔符、條形圖及另外一個(gè)分隔符。條形符列的各行中是另外一個(gè)表。這些嵌套表有兩個(gè)單元格:第一個(gè)單元格為藍(lán)色,第二個(gè)單元格為白色。藍(lán)色單元格的寬度為文盲率,白色單元格的寬度為 100% 減文盲率。結(jié)果得到簡(jiǎn)單的 HTML 條形圖,沒有任何圖像。
Region 下拉菜單有一個(gè) onchange 處理程序,只要選中新項(xiàng)目,此處理程序就會(huì)被調(diào)用。此時(shí),以當(dāng)前選中的值調(diào)用 plot 方法,圖形即被更新。
此代碼的兼容性非常好。所使用的 innerHTML 可用 createElement 和 appendChild 等 DOM 方法取代,可兼容所有現(xiàn)代瀏覽器。
條形圖的 PHP 代碼
在 PHP 中實(shí)現(xiàn)條形圖時(shí),本文著眼于如何從服務(wù)器的 PHP 代碼中獲取數(shù)據(jù)并將其置入 Dynamic HTML(DHTML)JavaScript 中。條形圖的 PHP 代碼如清單 2 所示。
清單 2. 條形圖的 PHP 代碼
<?php
$years = array( 1970, 1980, 1990, 1995, 2000, 2005, 2010, 2015 );
$countries = array();
$countries[ "World" ] = array( 36.6, 30.3, 24.7, 22.4,
20.3, 18.3, 16.5, 15.0 );
$countries[ "Africa" ] = array( 72.4, 62.4, 51.2, 45.6,
40.2, 35.2, 30.8, 26.8 );
$countries[ "America" ] = array( 14.8, 11.6, 9.0, 7.9,
6.9, 6.0, 5.3, 4.6 );
$countries[ "Asia" ] = array( 48.5, 38.7, 30.2, 27.2,
24.4, 21.8, 19.6, 17.7 );
$countries[ "Europe" ] = array( 6.4, 4.3, 2.8, 2.2,
1.8, 1.4, 1.1, 0.8 );
$countries[ "Oceania" ] = array( 11.1, 8.7, 7.1, 6.6,
6.1, 5.6, 5.3, 5.0 );
?>
<html>
<head>
<title>Bar Graph Example</title>
<script>
var years = [ <?php echo( join( ",", $years ) ); ?> ];
var rates = [];
<?php
foreach( $countries as $name => $values ) {
?>
rates[ ‘<?php echo($name) ?>‘ ] = [
<?php echo( join( ",", $values ) ); ?> ];
<?php } ?>
function plot( region )
{
var html = "";
html += "<table width=‘100%‘ cellspacing=‘0‘ cellpadding=‘1‘>";
for( var year in years )
{
var val = Math.round( rates[region][year] );
html += "<tr>";
html += "<td width=‘8%‘>"+years[year]+"</td>";
html += "<td width=‘1%‘ class=‘bar-start‘></td>";
html += "<td width=‘92%‘>";
html += "<table width=‘100%‘ cellspacing=‘0‘ cellpadding=‘0‘><tr>";
html += "<td width=‘"+val+"%‘ class=‘bar-on‘> </td>";
html += "<td width=‘"+(100-val)+"%‘ class=‘bar-off‘> </td>";
html += "</tr></table></td>";
html += "<td width=‘1%‘ class=‘bar-start‘></td>";
html += "</tr>";
}
html += "</table>";
document.getElementById( "graph" ).innerHTML = html;
}
</script>
<style>
body { font-family: arial, verdana, sans serif; }
.bar-on { background: blue; }
.bar-off { background: white; }
.bar-start { width:1px; background: black; }
#graph { width: 600px; }
</style>
</head>
<body onload="plot(‘World‘)">
Region: <select onchange="plot(this.options[this.selectedIndex].value)">
<?php
foreach( $countries as $name => $values ) {
?>
<option value="<?php echo($name) ?>"><?php echo($name) ?></option>
<?php } ?>
</select><br/><br/>
Rates of illiteracy (larger is worse):<br/><br/>
<div id="graph">
</div>
</body>
</html>
|
在文件頂端,為 years 和 countries 數(shù)組預(yù)先加載年份、國(guó)家列表及其掃盲值。隨后,PHP 需要生成 DHTML 代碼的三個(gè)區(qū)域。第一個(gè)填充 JavaScript 中的 years 數(shù)組,第二個(gè)填充 rates ,第三個(gè)以國(guó)家名設(shè)置 <select> 標(biāo)記的內(nèi)容。
散點(diǎn)圖
動(dòng)態(tài)創(chuàng)建新 HTML 是 DHTML 的核心。選擇之一是構(gòu)建字符串并在頁(yè)面上設(shè)置元素的內(nèi)部 HTML。本例給出了第二種方法,使用散點(diǎn)圖作為示例。圖 3 展示了一個(gè)簡(jiǎn)單等式的散點(diǎn)圖。
圖 3. 多周期正弦波形圖
您可更改等式,并單擊 Try It! 按鈕更新圖形,如圖 4 所示。
圖 4. 略有差異的等式圖形
所有這一切都不必返回 PHP 服務(wù)器。本例甚至沒有用到服務(wù)器 —— 您可以新建一個(gè) HTML 文件,開始編寫 HTML 代碼。本圖的實(shí)現(xiàn)代碼如清單 3 所示。
清單 3. 散點(diǎn)圖代碼
<html>
<head>
<title>Dynamic Graphing Example</title>
<style type="text/css">
body { font-family: arial, verdana, sans serif; }
#graphdiv {
height:500px; width:500px;
border:1px solid black;
position:relative;
}
</style>
<script>
function drawgraph()
{
var g = document.getElementById( "graphdiv" );
var eq = document.getElementById( "eq" ).value;
var dx = [];
var dy = [];
var sx = 10000;
var ex = -10000;
var sy = 10000;
var ey = -10000;
for( var i = 0; i < 100; i++ )
{
var x = i / 100;
var y = eval( eq );
if ( y > ey ) ey = y;
if ( y < sy ) sy = y;
if ( x > ex ) ex = x;
if ( x < sx ) sx = x;
dx.push( x );
dy.push( y );
}
var gwidth = 500;
var gheight = 500;
var imgwidth = 100;
var imgheight = 100;
var fx = (gwidth-(imgwidth/2))/(ex-sx);
var fy = ((gheight-(imgheight/2))/2)/(ey-sy);
g.innerHTML = "";
for( i = 0; i < dx.length; i++ )
{
var x = ( dx[i] * fx );
var y = ((gheight-(imgheight/2))/2)+(dy[i]*fy);
var img = document.createElement( "img" );
img.src = "ball.gif";
img.style.position = "absolute";
img.style.top = y+"px";
img.style.left = x+"px";
g.appendChild( img );
}
}
</script>
</head>
<body onload="drawgraph()">
Equation:
<input type="text" id="eq" value="Math.sin(x*32)" />
<button onclick="drawgraph()">Try It!</button>
<br/><br/>
<div id="graphdiv">
</div>
</body>
</html>
|
本例的大部分代碼都位于 JavaScript 函數(shù) drawgraph 中。該函數(shù)創(chuàng)建兩個(gè)數(shù)字?jǐn)?shù)組 —— 一個(gè)存儲(chǔ) x 值,另外一個(gè)存儲(chǔ) y 值。x 軸的數(shù)字范圍為 0 到 1,y 軸的數(shù)字是通過將各 x 值代入等式計(jì)算得出的。
數(shù)據(jù)通過等式生成,但代碼為各軸設(shè)置了最小值和最大值,并按此自動(dòng)調(diào)整數(shù)據(jù)。
將圖像置入圖形需要用到一種新技術(shù):我們使用 document.createElement 來構(gòu)建一個(gè) <img> 標(biāo)記,隨后使用 appendChild 將新創(chuàng)建的 img 對(duì)象添加到圖形對(duì)象中。這項(xiàng)技術(shù)要優(yōu)于使用字符串設(shè)置 innerHTML ,因?yàn)榇a更易于閱讀和維護(hù) —— 而且您不必?fù)?dān)心字符串編碼問題。
使用 createElement 的技術(shù)符合 World Wide Web Consortium(W3C)Document Object Model(DOM)規(guī)范,也是動(dòng)態(tài)創(chuàng)建 HTML 元素的首選方法。
散點(diǎn)圖的 PHP 代碼
散點(diǎn)圖示例自成體系。PHP 代碼將散點(diǎn)圖打包為組件。該組件的代碼如清單 4 所示。
清單 4. 散點(diǎn)圖的 PHP 代碼
<?php
function graph_header()
{
?>
<style type="text/css">
body { font-family: arial, verdana, sans serif; }
#graphdiv {
height:500px; width:500px;
border:1px solid black;
position:relative;
}
</style>
<script>
function drawgraph()
{
var g = document.getElementById( "graphdiv" );
var eq = document.getElementById( "eq" ).value;
var dx = [];
var dy = [];
var sx = 10000;
var ex = -10000;
var sy = 10000;
var ey = -10000;
for( var i = 0; i < 100; i++ )
{
var x = i / 100;
var y = eval( eq );
if ( y > ey ) ey = y;
if ( y < sy ) sy = y;
if ( x > ex ) ex = x;
if ( x < sx ) sx = x;
dx.push( x );
dy.push( y );
}
var gwidth = 500;
var gheight = 500;
var imgwidth = 100;
var imgheight = 100;
var fx = (gwidth-(imgwidth/2))/(ex-sx);
var fy = ((gheight- (imgheight/2))/2)/(ey-sy);
g.innerHTML = "";
for( i = 0; i < dx.length; i++ )
{
var x = ( dx[i] * fx );
var y = ((gheight-(imgheight/2))/2)+(dy[i]*fy);
var img = document.createElement( "img" );
img.src = "ball.gif";
img.style.position = "absolute";
img.style.top = y+"px";
img.style.left = x+"px";
g.appendChild( img );
}
}
</script>
<?php
}
function graph_place()
{
?>
</head>
<div id="graphdiv">
</div>
<?php
}
?>
|
此代碼定義了兩個(gè)函數(shù):graph_header 和 graph_place 。graph_header 函數(shù)應(yīng)在文檔的開頭部分調(diào)用,graph_place 則應(yīng)在您需要加入圖形的地方調(diào)用。清單 5 展示了更新的圖形頁(yè)面代碼。
清單 5. 更新的散點(diǎn)圖 PHP 代碼
<?php
require_once( "graph_component.php" );
?>
<html>
<head>
<title>Dynamic Graphing Example</title>
<?php graph_header(); ?>
</head>
<body onload="drawgraph()">
Equation:
<input type="text" id="eq" value="Math.sin(x*32)" />
<button onclick="drawgraph()">Try It!</button>
<br/><br/>
<?php graph_place(); ?>
</body>
</html>
|
這比原始頁(yè)面要簡(jiǎn)單得多。首先將組件代碼包含進(jìn)來。隨后調(diào)用 graph_header 來添加 JavaScript 和 CSS。最后在希望將圖形放置在頁(yè)面上的地方調(diào)用了 graph_place 函數(shù)。
DHTML 能走多遠(yuǎn)?
JavaScript 代碼的強(qiáng)大與簡(jiǎn)單非常吸引人。但問題很快發(fā)生了變化,不再是插入的代碼有多么少,而是革新的路能走多遠(yuǎn)。Google Maps(參見 參考資料)是 DHTML 應(yīng)用程序的典范,它證明了 DHTML 應(yīng)用程序不僅在站點(diǎn)上有用,而且可集成到任何 Web 頁(yè)面上 —— 只需編寫一些簡(jiǎn)單的 JavaScript。但 Google 并沒有就此止步:它又創(chuàng)建了 Gmail(參見 參考資料),將 DHTML 的應(yīng)用擴(kuò)展到創(chuàng)建易于使用的郵件客戶端 —— 就在瀏覽器中。(或許您的 JavaScript 無(wú)法成就至此,但如果您確實(shí)投入時(shí)間去努力,也會(huì)欣喜地發(fā)現(xiàn)能取得怎樣的成果。)
每一名 DHTML 程序員都應(yīng)該鉆研的一項(xiàng)技術(shù)就是 Asynchronous JavaScript and XML(Ajax)。Ajax 為瀏覽器帶來了后臺(tái)處理 Web 請(qǐng)求的能力。這意味著,您的 DHTML 應(yīng)用程序可回調(diào)到 PHP 應(yīng)用程序,而不需刷新頁(yè)面。隨后頁(yè)面可使用那些數(shù)據(jù)刷新所顯示的信息 —— 完全不會(huì)使瀏覽頁(yè)面的用戶感覺不快。(關(guān)于 Ajax 文章與教程的相關(guān)信息,請(qǐng)參見 參考資料 部分。)
結(jié)束語(yǔ)
“使用 PHP 和 DHTML 設(shè)計(jì) Web 2.0 應(yīng)用程序” 系列的上一篇文章從新的時(shí)髦詞 Web 2.0 展開討論。而業(yè)界的另一重要時(shí)髦詞就是富客戶機(jī)應(yīng)用程序。兩者同樣意味著極酷的 Web 應(yīng)用程序,您可以同樣的方式看待它們。大量技術(shù)日益涌現(xiàn),目標(biāo)都是創(chuàng)建功能豐富的 Internet 應(yīng)用程序。Laszlo 和 MXML 大大簡(jiǎn)化了 Flash 的構(gòu)建,Microsoft? 的 Vista 也引入了一些新理念。但就構(gòu)建功能豐富的 Internet 應(yīng)用程序而言,DHTML 依然是最有誘惑力的,原因就在于您可以使用 PHP 這樣的現(xiàn)有技術(shù)來完成這一使命。
本文示范了通過簡(jiǎn)單的 CSS 和 JavaScript 豐富客戶體驗(yàn)的幾種方法。您可以在現(xiàn)有 Web 應(yīng)用程序中實(shí)現(xiàn)同樣的目標(biāo) —— 立即開始一個(gè) <script> 標(biāo)記,享受樂趣吧。
參考資料
學(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。他的作品還包括三十多篇文章。
|
|