jquery.jsを読み解く

第4回 jQueryライブラリ(770行目~1093行目)

この記事を読むのに必要な時間:およそ 9 分

jQuery.jsを読み解くの連載も今回で第4回となりました。

本題に入る前に少々豆知識です。jQueryは軽量なライブラリだと言われていますが,実際のところはどうなのでしょうか。ソースコードの行数をprototype.jsと比較してみると,prototype.jsの3,277行に対して,jQuery 1.2.2は3,383行です。ちょっと意外ですが,実はjQueryのほうが行数でみると多かったりします。行数が多いからといって高機能とはいえませんが,ライブラリを選択する際の参考にしてみてください。

それでは,さっそく続きのコードを見ていきましょう。

swap()

0770: // A method for quickly swapping in/out CSS properties to get correct calculations
0771: swap: function( elem, options, callback ) {
0772:   var old = {};
0773:   // Remember the old values, and insert the new ones
0774:   for ( var name in options ) {
0775:     old[ name ] = elem.style[ name ];
0776:     elem.style[ name ] = options[ name ];
0777:   }
0778:
0779:   callback.call( elem );
0780:
0781:   // Revert the old values
0782:   for ( var name in options )
0783:     elem.style[ name ] = old[ name ];
0784: },
0785:

jQuery.swapメソッドは,要素の大きさなどの属性を取得する際に,一時的に値を変更するための内部処理用メソッドです。次に説明するcssメソッドから利用されます。動作としては,774行目のfor文で古い値を保存しておいてから,引数optionsで渡された値に変更します。そして,779行目で引数として指定されたcallbackメソッドを実行します。最後に782行目のfor文で,属性を保存しておいた値に戻して完了です。

css()

0786: css: function( elem, name, force ) {
0787:   if ( name == "width" || name == "height" ) {
0788:     var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ];
0789:   
0790:     function getWH() {
0791:       val = name == "width" ? elem.offsetWidth : elem.offsetHeight;
0792:       var padding = 0, border = 0;
0793:       jQuery.each( which, function() {
0794:         padding += parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
0795:         border += parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
0796:       });
0797:       val -= Math.round(padding + border);
0798:     }
0799:   
0800:     if ( jQuery(elem).is(":visible") )
0801:       getWH();
0802:     else
0803:       jQuery.swap( elem, props, getWH );
0804:     
0805:     return Math.max(0, val);
0806:   }
0807:   
0808:   return jQuery.curCSS( elem, name, force );
0809: },
0810:

jQuery.cssメソッドは,選択された要素のスタイル属性値を取得するためのメソッドです。787行目にあるように"width"と"height"の値を取得したい場合だけ少し挙動が異なります。この2つの値を取得する場合で,対象となる要素がvisibility:"hidden", display:"none"など不可視状態の場合,先ほど説明したjQuery.swap()を呼び出して一時的にvisibility:"hidden", display:"block"の状態を作り出しています。こうしておいてから,790行目の関数getWH()で値を算出します。

また,"width"と"height"以外の値を取得する場合は,次に説明するjQuery.curCSS()を実行します(808行目)。

curCSS()

jQuery.curCSSメソッドは,CSSの属性値を取得します。Internet ExplorerやFirefox,Operaといったブラウザごとの解釈の違いに対する対策が随所に見られます。cssのクロスブラウザに対する処理をまとめている部分となります。

0811: curCSS: function( elem, name, force ) {
0812:   var ret;
0813:
0814:   // A helper method for determining if an element's values are broken
0815:   function color( elem ) {
0816:     if ( !jQuery.browser.safari )
0817:       return false;
0818:
0819:     var ret = document.defaultView.getComputedStyle( elem, null );
0820:     return !ret || ret.getPropertyValue("color") == "";
0821:   }
0822:
0823:   // We need to handle opacity special in IE
0824:   if ( name == "opacity" && jQuery.browser.msie ) {
0825:     ret = jQuery.attr( elem.style, "opacity" );
0826:
0827:     return ret == "" ?
0828:       "1" :
0829:       ret;
0830:   }
0831:   // Opera sometimes will give the wrong display answer, this fixes it, see #2037
0832:   if ( jQuery.browser.opera && name == "display" ) {
0833:     var save = elem.style.display;
0834:     elem.style.display = "block";
0835:     elem.style.display = save;
0836:   }
0837:   
0838:   // Make sure we're using the right name for getting the float value
0839:   if ( name.match( /float/i ) )
0840:     name = styleFloat;
0841:

815行目は,Safariブラウザでcolorの値がうまく取得できない時にtrueを返す関数です。後で処理を切替える判定条件として利用されます。

824行目は,Internet Explorerでopacityを取得した際の挙動を他のブラウザと合わせるための処理です。

832行目は,Operaがときどき間違ったdisplay値を返す問題への対応です。不思議なことにdisplay値を設定し直すことで解消するようです。

838行目は,float値を取得する際にIEだけプロパティ名が異なるための処理です。styleFloatは1206行目で定義されていて,IEの場合はstyleFloatを利用します。

0842:   if ( !force && elem.style && elem.style[ name ] )
0843:     ret = elem.style[ name ];
0844:

forceがfalseか指定されていない場合は,そのまま取得した結果を返します。

0845:   else if ( document.defaultView && document.defaultView.getComputedStyle ) {
0846:
0847:     // Only "float" is needed here
0848:     if ( name.match( /float/i ) )
0849:       name = "float";
0850:
0851:     name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase();
0852:
0853:     var getComputedStyle = document.defaultView.getComputedStyle( elem, null );
0854:
0855:     if ( getComputedStyle && !color( elem ) )
0856:       ret = getComputedStyle.getPropertyValue( name );
0857:
0858:     // If the element isn't reporting its values properly in Safari
0859:     // then some display: none elements are involved
0860:     else {
0861:       var swap = [], stack = [];
0862:
0863:       // Locate all of the parent display: none elements
0864:       for ( var a = elem; a && color(a); a = a.parentNode )
0865:         stack.unshift(a);
0866:
0867:       // Go through and make them visible, but in reverse
0868:       // (It would be better if we knew the exact display type that they had)
0869:       for ( var i = 0; i < stack.length; i++ )
0870:         if ( color( stack[ i ] ) ) {
0871:           swap[ i ] = stack[ i ].style.display;
0872:           stack[ i ].style.display = "block";
0873:         }
0874:
0875:       // Since we flip the display style, we have to handle that
0876:       // one special, otherwise get the value
0877:       ret = name == "display" && swap[ stack.length - 1 ] != null ?
0878:         "none" :
0879:         ( getComputedStyle && getComputedStyle.getPropertyValue( name ) ) || "";
0880:
0881:       // Finally, revert the display styles back
0882:       for ( var i = 0; i < swap.length; i++ )
0883:         if ( swap[ i ] != null )
0884:           stack[ i ].style.display = swap[ i ];
0885:     }
0886:
0887:     // We should always get a number back from opacity
0888:     if ( name == "opacity" && ret == "" )
0889:       ret = "1";
0890:

IEにはdocument.defaultView.getComputedStyleがないため,ここはIE以外で行われる処理になります。848~851行目は,属性名の正規化を行います。例えば,floatが含まれるものをfloatに統一したり,"paddingTop"を正規表現で"padding-top"にしたりします。次に855行目ですが,getComputedStyleが,利用可能で先ほどのcolor()の結果がfalseならば(Safariの問題が発生しなければ),getPropertyValueを使って値を取得します。

860行目以降はSafariが適切な値を返さない場合の処理で,親要素でdisplay:hiddenなものを一度display属性値をblockに設定してから値を取得しています。

著者プロフィール

山下英孝(やましたひでたか)

大学を卒業後,大手SIerに就職し,電機メーカーの研究所勤務を経て,ウノウに入社。1年半に渡ってWebサイトの開発,ディレクション,運用を経験した後に独立。2008年2月よりフリーエンジニアとして活動中。好きな言語はJavaScriptとPythonで,Linuxサーバ運用管理も得意。

ブログWeboo! Returns.

コメント

コメントの記入