2005-09-17

Javascript+HTML のデザインパターン

僕もご多分に漏れず Javascript で遊んだり調べたりしています。 いろいろなクールなサイトの生 Javascript を見て勉強しているのですが、 まず面白いなと思ったのがロールオーバーの実現方法です(JavaScript や HTML をわかってる人には当たり前の内容だと思うので、ツマラナイ話だと思いますが)。

WaSP の左上の画像のロールオーバーは

<img id="logo" src="/img/logo.gif" height="100" width="103"
  alt="Web Standards Project logo" />

生 HTML はこんなかんじで onmouseover/onmouseout 属性を記述せず、 JavaScript

function initRollOvers() {
 var logo;
 if (document.getElementById) {
  logo = document.getElementById('logo');
 } else {
  return false;
 }
 /*if (document.all) {*/
  logo.onmouseover = swapI;
  logo.onmouseout = swapI;
 /*} else {
  logo.addEventListener('mouseover',swapI,false);
  logo.addEventListener('mouseout',swapI,false);
 }*/
  return true;
}

function swapI(e) {
 e = (e) ? e : event;
 thisI = (e.srcElement) ? e.srcElement : e.target;
 if((thisI.status != 'a') &&
    (thisI.status != 'p')) {
  thisI.src = '/img/' + thisI.id + '_a.gif';
  thisI.status='a';
 } else if(thisI.status != 'p') {
  thisI.src='/img/'+thisI.id+'.gif';
  thisI.status='';
 }
}

こんな風にして id 属性に logo という画像を持つ img 要素の onmouseover と onmouseout をページ表示時に動的に変更することで実現していました。

似たような手法は Nikon のサイトYamaha のサイトでも 利用されています(両方同じ業者さんみたい)。

もう一つ、今度は別のところで、これと似た手法を見ました。

del.icio.us では delete リンクをクリックしたときに ちょっとした工夫をしているのですが、 このちょっとした工夫は下記のように実現されています。

delete リンクの HTML ソースはこんなかんじ。

<a href="/yohei?delete=9d7b7c953b1e47a7d82e791848f43899"
  class="rm" rel="nofollow">delete</a>

onclick 属性がなく Javascript の影も形もありません。

どうなっているかというと、ヘッダでロードしている Javascript

function rmPostAddEvent() {
  var all = getElementsByClass(document.getElementById('posts'),'rm','a')
  for(var i = 0, o; o = all[i]; i++) o.onclick = function(){ return rmPost(this) }
}
function rmPost(o) {
  o.style.display = 'none'
  var s = document.createElement('span'); s.o = o
  s.innerHTML = '<span class="important">delete this post?</span> <a href="'+o.href+'">yes</a> / <a 

href="'+o.href.replace(/(\?|&)delete=[^&]*&?/,'$1')+'" 

onclick="this.parentNode.o.style.display=\'inline\';this.parentNode.parentNode.removeChild(this.parentNode);return 

false">no</a>'
  o.parentNode.insertBefore(s, o)
  return false
}

とやって、yes/no を追加しています。

ロールオーバーの例と del.icio.us の例で共通するのは、 静的なコンテンツ部分(HTML)と動的な UI の振る舞い制御部分(JavaScript)を 完全に別ファイルに分けているところです。 もちろんこうするためには class 属性や id 属性の値にコンベンションが必要となるのですが、 このようにアクションとコンテンツを分離することで、以下のようなメリットがありそうです。

コンテンツ生成プログラムの効率化
onmouseover などイベント系の属性を記述しないですむので、HTML 生成プログラムが効率化しそうです
メンテナンス性の向上
上の項目につながりますが、問題があるのがデータなのか、スクリプトなのかの区別がつきやすそうです
HTML サイズの縮小
要素毎に属性を記述しないですむので、ネットワーク転送量が減少します

さらに、class や id の値のコンベンションという意味で、microformats との相性もよさそうです。

さらに面白いと思ったのは、 この動的・静的がサーバから見たときと、クライアントから見たときにちょうど対称的になっているところです。 サーバから見ると、生成するデータ(ブックマーク一覧)こそが動的であり、 そこに yes/no リンクという振る舞いを与える JavaScript プログラムは静的です(del.icio.us の URL にも static とある)。 逆にクライアント(ブラウザ)から見ると、 HTML に入っているブックマーク一覧というデータは静的ですが、 JavaScript によってそれらを動的に変更しています。

こういうのってかなり抽象化できていて、正にデザインパターンと呼べそうな気がするのですが、 何か名前があるんでしょうか(NDO メソッド)。ちょっと探してみたけれど、見つけられませんでした。 勝手に behavior injection(振る舞いの注入) とか action injection (アクションの注入) と想像して検索してみたのだけれど。

2 件のコメント:

  1. > こういうのってかなり抽象化できていて、正にデザインパターンと呼べそうな気がするのですが

    考え方的にはアスペクト指向、実装的にはobserverパターンなのではないでしょうか。

    返信削除
  2. gorou さん、コメントありがとうございます。
    なるほど考え方は確かにアスペクト指向っぽいですね。参考になります

    返信削除