Javascriptライブラリ'prototype.js'のabsolutize()メソッド或はrelativize()メソッドは視覚上の位置は変えることなく要素の配置方法だけを'absolute'もしくは'relative'に変えてくれる便利な(例えば、その要素をドラッグしたい時等は'static'のままだと無理)メソッドだ。
ただし、absolutize()メソッドはループの中で使うと思った結果にならない。
例えば下記のような簡単なHTMLコードがあったとする。
<img src="AAA.JPG" alt="AAA" /> <img src="BBB.JPG" alt="BBB" /> <img src="CCC.JPG" alt="CCC" /> <img src="DDD.JPG" alt="DDD" />
これらimg要素のpositionはすべてstaticだとする。 そしてそれらに対して下記のスクリプトを実行してみる。
$('img').each(function(elem) { elem.absolutize(); });
すると結果は4枚とも同じ位置に来てしまう。
要は視覚上の位置が変わってしまう訳だ。
なぜそうなるのかよくよく考えてみるとちゃんとした理由がある。
そして理由がわかってしまえば全然納得のいく話なのだがつまりはこういう事だ。
要素オブジェクト「$('img')」をeach()に渡す時はDOMの上から順番に渡していく事になる。
この場合はまず"AAA.JPG"が渡される。
そして"AAA.JPG"に対してabsolutize()メソッドが実行される。
absolutize()のイメージとしては(簡単に)
- まず、その要素の親要素からの相対位置を記憶しておく(top,left)
- そして要素の配置方法を'absolute'に変える(要素.style.position = 'absolute';)
- 要素のtopプロパティとleftプロパティに先ほど記憶しておいた値を設定する
と、こんな感じだと僕は捉えている。
最初の要素("AAA.JPG")の元々の相対位置が(top:0,left:0)だとしたら'absolute'に変わった後のtopプロパティとleftプロパティも0になる。
で、次の要素("BBB.JPG")に移る訳だがここで注意が必要。
例えば"BBB.JPG"の元々の視覚上の位置が(top:0,left:120)だったとしてもこの時点では(top:0,left:0)に変わってしまっている。
なぜかというと、最初の要素("AAA.JPG")が'absolute'に変わった時点で通常のレイアウトからは独立してしまっているからだ。
いままで"AAA.JPG"が長男だったがもういなくなっちゃったので"BBB.JPG"が長男になっちゃった。みたいな感じだ。
そして結局はその流れの繰り返しになるのですべての要素は(top:0,left:0)になってしまう。
という事。
この場合、ループを2回まわす事で対処する事はできる
1回目のループはtopプロパティとleftプロパティの取得。そしてtopプロパティとleftプロパティの設定(この時点ではまだposition:staticなので視覚上の位置は変わらず)。
2回目のループでabsolutize()メソッドの実行。
これで目的は達成出来るがループを2回処理している時点でなんか嫌な感じがする。
もう一つの対処法としてeach()に渡す前に「$('img')」を逆さにしておく方法がある。
通常のJavascriptで得られる要素オブジェクト群(document.getElementsByTagName等から得られるNodeListといわれる物)は配列のようで配列ではないので、例えば配列用のメソッド(Array.shiftやArray.join)は使えない。
ただしPrototype.jsはそのへんもきっちりと拡張してくれているので、
$('img').reverse().each(function(elem) { elem.absolutize(); });
こうする事が出来る。
こうすれば最後の要素から処理してくれるので、この場合兄弟オブジェクトのレイアウトに変更は生じない。
下記のサンプルを実行すれば違いが一発で分かる。
左側が通常のループ処理。
右側はreverse()処理を施したループ処理。
各要素は'absolute'した後はドラッグして動かす事が出来る。
Click!!
Click!!
カテゴリ:
トラックバック(0)
トラックバックURL: http://blog.beanz-net.jp/beanz_mtos/mt-tb.cgi/66
コメントする