本文へジャンプ

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


お客様が developerWorks に初めてサインインすると、プロフィールが作成されます。プロフィールで選択した情報は公開されますが、いつでもその情報を編集できます。お客様の姓名(非表示設定にしていない限り)とディスプレイ・ネームは、投稿するコンテンツと一緒に表示されます。

送信されたすべての情報は安全です。

  • 閉じる [x]

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


送信されたすべての情報は安全です。

  • 閉じる [x]

PHPとDHTMLを使用したWeb 2.0アプリケーションの開発 第1回: 自分で試してみよう

Jack Herrington (jherr@pobox.com), Senior Software Engineer, Leverage Software
Jack D. Herringtonは、20 年以上の経験を持つシニア・ソフトウェア・エンジニアです。彼の著書には、『Code Generation in Action』、『Podcasting Hacks』、『PHP Hacks』の 3 冊があります。また、30 を超える記事も執筆しています。

概要: 2006年の流行語大賞はWeb 2.0で決まりです。この言葉の定義については熱い議論が戦わされていますが、これは先進の動的Webアプリケーションを指す言葉のようです。PHPで開発されることの多いこうしたWebアプリケーションでは、動的HTML (DHTML) を使用してWebページが作成されます。こうして作成されたページでは、ページ間の移動や変更の際にサーバーまで戻って更新処理を行う必要がなくなります。この記事では、PHPとDHTMLを使用したWeb 2.0アプリケーションの開発方法をJack Herringtonがシリーズで説明していきます。

日付:  2006年 5月 02日
レベル:  中級 この記事の原文:  英語
アクティビティー: 1684 ビュー
お気軽にご意見・ご感想をお寄せください: 


DHTMLとは、JavaScriptコードを備えたHTMLのことです。JavaScriptコードを使用してブラウザーのページのコンテンツやレイアウトを変更する場合、サーバーに戻って処理を行う必要はありません。HTMLページを記述する場合、実際にはオブジェクト・ツリーを記述することになります。<table> タグ や <p> タグなどのすべてのタグは、JavaScript領域ではオブジェクトとして処理されます。JavaScriptを使用すると、タグの内容、カスケーディング・スタイル・シート (CSS) のスタイル、ロケーションなどを、すべてサーバーに戻ることなく変更することができます。DHTMLとは、HTMLとCSSとJavaScriptの交差点のようなものです。

DHTMLを使用する技術は、JavaScriptコードがブラウザーに追加されて以来ずっと存在してきましたが、その技術のサポートに関しては不十分なものでした。初期のMicrosoft (R) Internet Explorerでは優れたサポートが提供されていましたが、同じ時期のNetscape V4ではDHTML技術はサポートされていませんでした。最近では、MozillaとFirefoxが安定したDHTMLのサポートを強化しています。この分野に関して、Internet Explorerは大きく立ち遅れたと考える人もいます。

DHTMLの利点と欠点

JavaScriptをWebページに組み込むことにより、ページの機能が動的になり、使い勝手が向上します。より多くのデータをより短時間で取得し、さまざまな角度から情報を参照し、サイト内をスムーズに検索することができるようになります。そして、このサイトは多くのページのためにサーバーに戻る必要がありません。

しかし、JavaScriptの使用を避けなければならない理由もあります。それは、ブラウザーの互換性です。初期の単純HTMLでは、Internet ExplorerとNetscapeではページの構造が異なっていました。この問題は修正されましたが、CSSに対するサポートが追加された際に、互換性に関する新たな問題が発生しました。現在のところ、CSSに関する問題はその大部分が修正されましたが、今度はJavaScriptの互換性に関する問題が浮上してきています。

こうした互換性に関する問題の解決は容易ではありません。JavaScriptがもたらす利点と、JavaScriptをサポートする際にテストが必要になるブラウザーの数とを比較して、よく考えてみる必要があります。

以下に、JavaScriptを使用する際の注意点をいくつか記します。

  • JavaScriptはできる限り単純なものにすること。
  • 互換性の問題が発生したら、Web上で最適な解決方法を検索すること (詳しく調査された解決策が見つかることがよくあります)。
  • サポート対象外のブラウザーに対する予備のプレーンHTMLを用意しておくこと。
  • サポート対象のブラウザーとそのバージョン番号の一覧を作成すること。
  • Internet Explorerの機能を、MacとMicrosoft Windows(R) の両方で確認すること。

この記事で取り上げる例はできる限り単純で明確なものにしていますが、Firefox上でしかテストしていないため、互換性に関する問題がいくつか発生します。こうした問題を実際に体験し、そこから解決策を学んでください。

DHTMLを実装する際に一番簡単な方法は、最初にDHTMLをプレーンHTMLページに記述する方法です。この際、PHPやその他のサーバー側言語は使用しません。次に、こうして記述したコードをPHPコード用のテンプレートとして使用してDHTMLを生成します。この方法ならば、コードの基本機能を確認しながら、サーバー側の問題とクライアント側の問題を分離することができます。この記事の各例では最初にHTMLのコードを示し、次にPHPを使用してこのコードを示します。



広告ボックス

最初の例は、単純で互換性のある広告用フローティング・ボックスです。図1は、[Close] ボタンが設定された広告ボックスです。ページの前面に配置されています。



図1. 広告用フローティング・ボックス
広告用フローティング・ボックス

図2のように、[Close] ボタンをクリックすると広告ボックスが消えます。



図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? 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属性は、ページの左上隅を基準としたボックスの表示位置を指定します。

ボックスを非表示にする場合、closeアンカー・タグに特定のJavaScriptコードを設定します。この場合、httpプロトコルを使用する代わりにjavascriptプロトコルを使用してclosead関数を呼び出します。呼び出されたJavaScriptのclosead関数は、ad <div> に対するオブジェクト参照を取得し、CSSスタイルのvisibility属性をvisibleからhiddenに変更します。その結果、広告ボックスが非表示になります。

この例では、DHTMLの基本原則がいくつか示されています。その1つは、id属性の使用です。ある項目を動的に参照する場合、id属性を使用して固有のIDをその項目に設定します。この場合、広告ボックスにはadというIDを設定します。次に、document.getElementByIdメソッドを使用して、広告ボックス用の <div> オブジェクトに対する参照を取得します。

またこの例では、アンカー・タグで使用することができるjavascript疑似URLも示されています。この疑似URLを使用すると、リンクを挿入したすべての場所でJavaScriptを呼び出すことができます。

こうした技術は、その他のブラウザーでも機能します。現在使用されているすべてのブラウザーでは、JavaScript、CSS、絶対配置、実行時におけるvisibility属性などの動的要素の設定がサポートされています。



PHPでの広告ボックス

DHTMLで広告ボックスのコードを生成したら、次にこのコードをPHPで実装する方法について見ていきます (リスト2を参照)。広告ボックスに対する操作としては、ボックスの表示/非表示しかありません。そのためPHPコードでは、広告ボックスの動作を1つの関数呼び出しにまとめて記述します。状況に応じて、ページからこの関数が呼び出されるかどうかが決定されます。


リスト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>

このコードで新たに設定されたPHPのplace_ad関数は、変更可能なタイトル文字列を広告ボックスに設定し、このボックスをページ上に配置します。複数のページに広告を表示したい場合は、この関数を個別のファイル (ページに広告の挿入が必要な際に、個別にインクルードするファイル) に格納します。



ポップアップ

フローティング・ボックスの別の形態として、ポップアップがあります。ユーザーが追加情報を要求した場合、ポップアップを使用してこの追加情報を表示することができます。図3に表示されているテキストを見てみましょう。



図3. 動物に関するプレーン・テキストのページ
動物に関するプレーン・テキストのページ

この画面から、キリン (giraffe) に関する追加情報を参照することができれば便利です。この「giraffe」というテキストには、簡単なリンクが埋め込まれています。このテキストをクリックすると、図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>

この例の場合、ポップアップ情報が設定されたポップアップの <div> は最初に非表示として定義され、ページの左上 (絶対位置) に配置されます。その後、「giraffe」テキストに設定されたアンカー・タグによってJavaScriptが呼び出され、ポップアップが呼び出されます。

JavaScriptメソッドのpopupは、word IDを使用して「giraffe」のテキストを検索します。次に、popupメソッドはoffsetLeft値とoffsetTop値を使用して、呼び出したポップアップをこのテキストの真下に配置します。このポップアップがすでに表示されている場合は、非表示にします。

popup <div> オブジェクトのinnerHTMLメンバーを設定することにより、ポップアップの内容を表示する前に、この内容を設定することができます。

このコードでは、ブラウザー間の互換性に関する問題はほとんど発生しません。ただし、offsetLeft値とoffsetTop値がブラウザー間で異なるため、これが原因で問題が発生する可能性があります。複雑にネストされたページの場合は、特に問題が起こりやすくなります。この場合、offsetParentオブジェクトを使用してoffsetLeft値とoffsetTop値を再帰的に追加し、HTMLオブジェクト・ツリーを上に移動する際に、各オブジェクトの親オブジェクトを取得する必要があるかもしれません。



PHPでのポップアップ

DHTMLコードを使用すれば、PHPアプリケーションで簡単にポップアップを使用することができます。リスト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>

この場合、ヘッダー部分の生成と各ポップアップの配置は個別の処理になります。ページからheadタグ内部のpopup_headerを呼び出し、id値に「popup」を設定して <div> タグを追加する必要があります。こうすると、ポップアップの要求があるたびに、ページからPHPのpopup関数が呼び出されます。

PHPのpopup関数には3つのパラメーターがあります。ポップアップのID、ポップアップを表示する項目のプレーン・テキストの値、その項目がクリックされたときにポップアップ表示するテキストの3つです。このように設定すると、元のDHTMLバージョンとほぼ同じアンカー・タグがpopup関数によって生成されます。

通常は複数のポップアップが1つのページに表示されることになるため、このコードではポップアップ内に表示されるテキストを指定するためのパラメーター (3つめのパラメーター) が追加されています。これを実装する場合、JavaScriptのpopup関数に追加のパラメーターを1つ指定します。こうすると、<div> タグのinnerHTMLがこの新しいパラメーター値に設定されます。



スピナー

ページ上のデータを表示したり非表示にしたりするもう1つの方法に、スピナーがあります。この場合、ページはいくつかのセクションに分割され、各セクションはスピナーの使用によって個別に表示と非表示を切り替えることができます。図5に2つのスピナー・セクションが設定されたページを示します。それぞれのスピナー・セクションは、最初は閉じた状態になっています。



図5. スピナーが閉じた状態のページ・セクション
スピナーが閉じた状態のページ・セクション

[Level One] セクションの [Open] リンクをクリックすると、図6のようにセクション内の内容が表示されます。



図6. 最初のスピナーが開いた状態のページ
最初のスピナーが開いた状態のページ

[open]または[closed]といった文字の代わりに、画像を使用することもできます。一般的に、右向きの三角形が閉じている状態を表し、下向きの三角形が開いている状態を表すことが多いようです。プラス記号とマイナス記号が使用される場合もありますが、この場合はプラス記号が閉じている状態を表し、マイナス記号が開いている状態を表します (どちらがいいかという議論は、MacとWindowsのどちらがいいかという議論と同じことです。MacとWindowsのどちらのスピナーも、2つの異なるオプションに対応しています)。

リスト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> の2つのグループは、それぞれのセクションとその内容を定義しています。一般的に、ヘッダー部分には「lev」というIDが設定され、その後に数字が続きます (例: lev2)。本体部分にも同じIDが設定され、その後に接尾語の「_body」が続きます。この場合、「lev2」はスピナーのリンク部分になり、「lev2_body」はスピナーの本体部分になります。

スピナーの制御部分はspin関数に記述されています。この関数によってスピナーの本体部分の表示/非表示の状態が確認され、表示されている場合は非表示に、非表示の場合は表示に、それぞれスピナーの状態が変更されます。

スピナーの項目を非表示にする場合はheight属性に0pxを設定し、スピナーの項目を表示する場合はheight属性にautoを設定する必要があります。Internet Explorerの場合、非表示になっている項目の領域は折りたためられますが、Firefoxの場合、非表示項目の領域はプレースホルダーとしてそのまま残ります。このため、非表示項目の領域を適切に折りたたむようにするには、height属性に0pxを設定する必要があります。

項目の状態 ([open]または[closed]) を表す際にテキストではなく画像を使用する場合、スピナー・オブジェクトのinnerHTML値を変更するコードを修正して、テキストの代わりにイメージ・タグを指定します。



PHPによるスピナー

PHPでスピナーを実装する場合、HTMLのセグメントを開始と終了の関数にまとめ、サーバー側でDHTMLコードを生成する場合の標準的なパターンに従います。リスト6にPHPのコードを示します。


リスト6. 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 = '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とタイトルという2つの引数が設定されています。end_spinner関数が呼び出されると、start_spinner関数でオープンされた <div> タグがクローズされ、スピナーの内容が保持されます。

スピナーの内容を3つめの引数として指定することもできますが、大抵の場合はこれらのセクションはややこしくなり、インターフェースの使用が複雑になってしまいます。動的セクションを開始と終了の関数にまとめる方法の場合、この2つの関数の間に記述するPHPコードが際限なく複雑なものになってしまう可能性があります。



タブ

表示内容の異なる部分を参照する場合によく使用されるもう1つの方法として、タブがあります。MetaCriticのサイト (「参考資料」を参照) から、軽いタブの例を参照することができます。このサイトではタブを使用して、ゲーム・リストを名前順またはレビュー・スコア順に切り替えて表示しています。その際、サーバーに戻って処理することはありません。図7に、このゲーム・リストの簡単な例を示します。



図7. 名前順のゲーム・リスト
名前順のゲーム・リスト

ゲーム・リストをレビュー・スコア順に表示したい場合は、[By Score] のリンクをクリックします。図8のように、リストの表示順が変更されます。



図8. スコア順のゲーム・リスト
スコア順のゲーム・リスト

クライアント側で複雑な並び替え処理を実行する代わりに、MetaCriticのサイトでは同等の機能を持った2つのフラッシュ・カードを使用しています。一方のカードには名前順にソートされたリストがあり、もう一方のカードにはスコア順にソートされたリストがあります。この状態でリンクをクリックすると、それぞれのカードが交互に表示/非表示を繰り返します。リスト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>

2つのリストは、namesとscoreという2つの <div> タグに記述されています。namesの <div> タグには名前順にソートされたゲーム・リストが入り、scoreの <div> タグにはスコア順にソートされたゲーム・リストが入っています。関数showは [By Name] リンクと [By Score] リンクに関連付けられています。どちらのリストも最初は非表示になっていますが、いずれかのリンクがクリックされると、そのリンクに対応するリストが表示されます。

このコードには、他にもいくつか面白い仕掛けがあります。まず、className属性を使用してリンクのCSSクラスを動的に変更していることに注目してください。クリックされたリンク・ボタンの色が白から黒に変わるのはこのためです。

次に、namesとscoreのCSSにも注目してください。どちらの <div> タグもコード上では左上の絶対位置に配置されていますが、実際に表示されるページ上の配置は左上ではありません。これは、<div> タグのID値に「container」が設定されているためです。このcontainerには「relative (相対位置)」という位置属性が指定されているため、<div> タグのcontainerによって、タグ内に定義されている項目の元の位置が置き換わります。その結果、テーブルはページ上の絶対位置ではなく、containerに対する相対位置に配置されることになります。

このタイプのDHTMLは処理が適度に複雑で、面白い機能を記述することもできます。また、現在使用されているほとんどのブラウザーに対しても互換性を持っています。



PHPでのタブ

PHPでDHTMLを開発する際の別の方法として、出力バッファリング (output buffering) を使用する方法があります。出力バッファリングはページ上のテキスト、タグ、echo要素を格納し、後から使用できるようにこの値を文字列として戻します。このタブを実装する場合、出力バッファリングを使用してタブの内容を文字列として保存し、その後ページ上にこの文字列をレンダリングします (リスト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という2つの変数の定義から始まっています。配列tabsには、各タブのid値、title値、html値が格納されます。current_tabは、start_tab関数とend_tab関数の呼び出しの間に生成されるタブをポイントします。start_tab関数には、タブのid値とtitle値の2つのパラメーターが設定されています。start_tab関数が呼び出されると、出力バッファリングが開始されます。

end_tab関数が呼び出されると、出力バッファリングが停止します。その際、配列tabsのcurrent_tab内のhtml値に結果の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アプリケーションによって表示されるページの周囲にこの要素を配置する方法について説明します。



参考文献

学ぶために

  • PHPに関することは、まずPHP.netを参照してください。

  • クライアント側コーディングのヒントについて検索する場合は、Ajaxian blogが便利です。

  • クライアント側処理を検索する場合は、Ajax Freaksのサイトも参照してください。

  • ブラウザーの互換性に関する問題についての参考情報や記事については、WebReference.comから参照できます。

  • O'Reilly Media社のサイトで紹介されている「 Dynamic HTML: The Definitive Reference 」は、動的HTMLを理解する際に最適な書籍です。

  • この記事で紹介しているサンプル・タブの例は、Metacritic.comから参照できます。

  • AJAXベースのWebアプリケーションを構築する方法については、developerWorksの記事「Build apps using Asynchronous JavaScript with XML (AJAX)」を参照してください。書籍を注文するサンプル・アプリケーションの構築を例に取り、ページ更新を必要としないリアルタイム確認機能を備えたアプリケーションの構築方法を説明しています。

  • PHPに関するさらに詳しい情報については、IBM のdeveloperWorksのサイトからPHP project resourcesのページを参照してください。

  • developerWorks technical events and webcastsのページから、最新技術を参照することができます。

  • developerWorksのOpen source zoneのページから、オープン・ソース技術による開発やIBM製品の使用に役立つハウツー情報やツール、プロジェクトの更新情報などの豊富な情報を参照することができます。

製品や技術を入手するために

  • IBMの体験版ソフトウェアをダウンロードできます (DVDもあり)。次回のオープン・ソース開発のプロジェクトに活用してください。

議論するために

著者について

Jack D. Herringtonは、20 年以上の経験を持つシニア・ソフトウェア・エンジニアです。彼の著書には、『Code Generation in Action』、『Podcasting Hacks』、『PHP Hacks』の 3 冊があります。また、30 を超える記事も執筆しています。

不正使用の報告のヘルプ

不正使用の報告

ありがとうございます。 このエントリーは、モデレーターの注目フラグが設定されました。


不正使用の報告のヘルプ

不正使用の報告

不正使用の報告の送信に失敗しました。


developerWorks: サイン・イン


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


お客様が developerWorks に初めてサインインすると、プロフィールが作成されます。 プロフィールで選択した情報は公開されますが、いつでもその情報を編集できます。 お客様の姓名(非表示設定にしていない限り)とディスプレイ・ネームは、投稿するコンテンツと一緒に表示されます。

表示名をお選びください

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

(半角英数字で3文字以上31文字以下にする必要があります)


「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


この記事を評価する

コメント

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Open source
ArticleID=237332
ArticleTitle=PHPとDHTMLを使用したWeb 2.0アプリケーションの開発 第1回: 自分で試してみよう
publish-date=05022006
author1-email=jherr@pobox.com
author1-email-cc=

タグ

Help
このタグで、My developerWorks のすべてのタイプのコンテンツを見つけるために検索フィールドを使用します。

スライダーバーを使用することで、より多く(少なく)タグを表示します。

人気のタグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するトップのタグを表示します。

マイ・タグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するお客様ご自身のタグを表示します。

このタグで、My developerWorks のすべてのタイプのコンテンツを見つけるために検索フィールドを使用します。人気のタグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するトップのタグを表示します。マイ・タグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するお客様ご自身のタグを表示します。