09 | 2017/10 |  11

  1. 無料サーバー

User forum-FC2BLOG-Info-Edit Template-Post-Edit-Upload-LogOut

CSSやJavascript自習の苦闘史を綴っていきたい。恐縮ですがJavascriptを有効にしてご覧ください。
2005年12月から社会問題も掲載!

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

 

jQuery() の挙動を解読する(29) jQuery で DOM エレメントの CSS 値を取得する upon ver1.3.2──jQuery解読(43)

jquery.js は jQuery.css() や jQuery.curCSS() クラスメソッドで、スタイル宣言されていない CSS スタイル値や未描画要素の CSS スタイル値を取得する

CSS 値はそれが明示的に style 宣言されている場合には elem.style.styleName で容易に所得出来ます。しかし明示的に宣言されていない限り、要素が隠蔽( display : none )されていたり、ブラウザによる描画前の時点では、当該要素の幅や高さは取得できません。

さて、jQuery サンプルで多用される 1 つのメソッドに jQuery(x).css(y) インスタンスメソッドがあります。これは jQuery(x) によって Web サイト内から抽出した DOM Nodes を対象として、y で指定された様々な CSS スタイルを設定したり、宣言されているスタイル値を取得する汎用的なメソッドです。

これに対して jQuery.css( elem, name, ・・・) は elem DOM Node の name スタイル属性値を取得するためのクラスメソッドで、このメソッドの前後に定義されている swap() メソッド(#734-#748)や curCSS() メソッド(#781-#845)と連携して、明示的にスタイルが宣言されていない場合や要素が隠蔽されている場合も含めて、スタイル値を取得します。

このエントリイでは jquery.js がどのように CSS 値の取得を行うのかを解読しようと思います。

なお、以下に登場するボックスモデルに係る名称は下図に拠ります。

ボックスモデルの寸法説明図

呼称は全て日本語化し、マージン辺、ボーダー辺、パディング辺、内容辺とします。

jQuery.css() クラスメソッド解読

■ jQuery.css() クラスメソッド ■
750: css: function( elem, name, force, extra ) {
    // 引数は順に、タグ要素、スタイル名称。force は算出スタイル値を求めか否か、
    // extra は内容辺、ボーダー辺またはマージン辺のどこまでのスタイル値を求めるか
751:  if ( name == "width" || name == "height" ) {
752:   var val, props = { position: "absolute", visibility: "hidden", display:"block" },
       which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ];
753:
754:   function getWH() {
755:    val = name == "width" ? elem.offsetWidth : elem.offsetHeight;
756:
757:    if ( extra === "border" )
758:     return;
759:
760:    jQuery.each( which, function() {
761:     if ( !extra )
762:      val -= parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
763:     if ( extra === "margin" )
764:      val += parseFloat(jQuery.curCSS( elem, "margin" + this, true)) || 0;
765:     else
766:      val -= parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
767:    });
768:   }
769:
770:   if ( elem.offsetWidth !== 0 )
771:    getWH();
772:   else
773:    jQuery.swap( elem, props, getWH );
774:
775:   return Math.max(0, Math.round(val));
776:  }
777:
778:  return jQuery.curCSS( elem, name, force );
779: },

jQuery.css() メソッドは次のようにして CSS 値を取得します。

  1. ユーザーが値を取得したいスタイル( name で指定)が幅か高さである場合(#751)

    この場合には Microsoft 社が IE において定義し、他のブラウザも追随した便利なメソッド offsetWidth あるいは offsetHeight を使って幅や高さを求めます。

    1. elem.offsetWidth 値があれば(#770)、つまり当該要素がブラウザで描画されていれば、getWH() を起動し、要素の幅又は高さを計測します。勿論、幅 or 高さのいずれを取得するかはユーザーが name で指定します。
    2. elem.offsetWidth 値が取得できない場合、そうなるのは描画されていないからですから jQuery.swap() を起動して、ブラウザ表示に変化が出ないように、要素の CSS スタイル設定を、「絶対配置・非表示かつブロック表示」に一時的に変更してから、getWH() メソッドを呼び出して当該要素のスタイル値を取得します。
    3. getWH() 関数内の処理……ボーダー辺までの幅か高さを求める場合を除き jQuery.curCSS() メソッドを呼び出して計測します。
      1. ボーダー辺までの幅か高さを求める場合には、offset 値はボーダー辺までの値ですから、offset 値をそのまま返します。(#757-758)
      2. マージン辺までの幅か高さを求める場合(#763-764)margin 値を offset 値に加算します。
      3. 内容辺までの幅か高さを求める場合(#761-762及び#765-766)パディング値とボーダー値を offset 値から差し引きます。
      4. パディング辺までの幅か高さを求めることは意味がないと考えたのでしょう、算出しません。
  2. ユーザーが取得したいスタイル名が幅でも高さでもない場合(#772)

    処理を jQuery.curCSS( elem, name, force ); に委ねます。(#778)

▲ToTop

jQuery.css() の肝は中で使用されている this にあり

さて、このメソッドは決して難解な箇所はありません。たった 1 つのことを除いては!

中で 3 箇所使用されている this が一寸見には何を指しているのか、大変わかりにくいのです。

前後の文脈から何を指すべきかは推測できますが、「どうしてこの this がそれを指すのか?」───それが暫く分かりませんでした。

解明の糸口は推測した内容と値から、逆に色々考えていて突如見えてきました。

Javascript の基本中の基本ですが、メソッド内で使用される this は、当該メソッドを呼び出したオブジェクトを参照します。

これを改めて踏まえて、css() クラスメソッド内で使用されている this について解明してみます。

上のコードで注目に値する箇所は getWH() です。その中では each() クラスメソッドが起動され、更にその中で curCSS() クラスメソッドが呼び出されていますが、3 カ所の this は全て getWH() 内の each() 内の curCSS() の引数内にあります。

要点は 3 つの this が全て each() クラスメソッド内にあって、jQuery.curCSS() クラスメソッドの引数となっていることです。

each メソッドは第 1 引数の配列要素毎にそれを呼び出し元にして、第 2 引数の関数を実行します。callback.call( arguments[0][i], arguments[1] ) です。

上のコードにおいて which は [ "Left", "Right" ] か又は [ "Top", "Bottom" ]です(#752)。これを第 1 引数として、第 2 引数である 760 ~ 766 行の関数が call されます。ですから呼び出された関数内で this はまず which を参照します。

しかし、呼び出された関数内部で更に別の関数 jQuery.curCSS() メソッドが起動されますから、この関数が起動した後は this は jQuery 関数オブジェクトを参照します。

しかし、this は jQuery.curCSS() メソッドの引数として登場しています。ここが肝心なところです。

もし this が jQuery.curCSS() メソッドの内部で使用されれば、それは this の仕様から jQueryを参照します。しかし、引数である this は無名関数内から jQuery.curCSS() メソッドに外挿され、投入されます。つまり、所与の値として付与されるのですから、このメソッドはそれを受け取って起動するわけで、受け取る時点では this は jQuery ではなく 巡回処理対象 which が参照するいずれかの要素を参照しているのです。

こうして this は "Left"、 "Right"、"Top"、あるいは "Bottom" に置き換えられることになります。

▲ToTop

jQuery.swap() クラスメソッド解読

このクラスメソッドは elem に対して、options による新たなスタイルを一時的に設定し、elem に設定されている CSS スタイルではなく、optionsによるその新たな CSS スタイルに callback( 実際には getWH ) 関数を適用します。

swap() メソッドは、jquery.js の中では css() メソッドからたった1度呼び出されるだけですが、隠蔽されているために、あるいは描画されていないために CSS スタイル値を取得できない要素のスタイル値を、ブラウザ表示を一切変えることなく取得するためのものです。つまり、要素の幅や高さを描画前に知るために使われます。

display:none が指定されている要素は、ブラウザから見れば存在しないことと同値です。また、ボックス内容領域幅よりも長いテキストノードは、暗黙的か明示的かに関わらず CSS スタイルが設定されていない限り、描画されなければその表示幅や高さは決まりません。

しかし、ブラウザ描画前に要素の高さや幅を知りたいケースは決して少なくありません。例えば mouseover 時のポップアップ表示はその好例です。popup は mouseover した要素の直近位置で、ブラウザ表示領域からはみ出さぬような位置に、適切な大きさの領域を表示させ、その中に解説文字などを示す場合に使用します。そのときには幅を指定し高さを文字数に応じて可変となるようにしますが、その大前提として事前に高さを知る必要があります。そうしないとポップ領域がウィンドウの上又は下にはみ出してしまうからです。

以上のようなケースに対処するための関数が、swap() メソッドです。

■ jQuery.swap() クラスメソッド ■
734: // A method for quickly swapping in/out CSS properties to get correct calculations
735: swap: function( elem, options, callback ) {
    // 引数は順にタグ要素、css() メソッド内で定義した要素の css style オブジェクト
    // callback は swapメソッド呼び出し時の引数定義により getWH() メソッドとなっている。
736:  var old = {}; // elem の本来のスタイルプロパティを記憶させるオブジェクト
737:  // Remember the old values, and insert the new ones
738:  for ( var name in options ) { // elem に設定されている各種スタイル値を
739:   old[ name ] = elem.style[ name ]; // old オブジェクトに複写する。
     // css() メソッド内で次の props が設定済みとなっている。
     // props = { position: "absolute", visibility: "hidden", display:"block" }
     // 第2引数 options に登録されているこの CSS 値を elem のスタイルオブジェクトに複写する。
740:   elem.style[ name ] = options[ name ];
741:  }
742:  // CSS 値計測用プロパティが追加された elem から callback 関数 getWH を呼び出す。
    // この処理の中で必要な CSS 値を取得する。
743:  callback.call( elem ); // css() から呼び出されたときには callback = getWH となっている。
744:
745:  // Revert the old values
746:  for ( var name in options ) //処理が終わったら記憶させてあるプロパティを
747:   elem.style[ name ] = old[ name ]; // elem に戻す。
748: },

▲ToTop

jQuery.curCSS() クラスメソッド解読

これはその名の通り Current CSS 値(算出スタイル値とも呼ぶ)を取得するメソッドで、jquery.js 内では css() メソッドなど 10 箇所から呼び出されています。

IE 以外の W3C 規格に準拠するブラウザの場合と、準拠を頑なに拒絶する IE の場合とで、全く異なる方法で CSS 現在値を取得しなければならないため、つまりクロスブラウザ対応を図る必要があるためコードが長くなっています。

■ jQuery.curCSS() メソッド ■
781: curCSS: function( elem, name, force ) { // force については後述する797行の解説を参照
782:  var ret, style = elem.style;
783:
784:  // We need to handle opacity special in IE
785:  if ( name == "opacity" && !jQuery.support.opacity ) { // IE の場合
786:   ret = jQuery.attr( style, " opacity" ); // 不透明度値を ret に取得する。
787:
788:   return ret == "" ? // 返値を決める。
789:    "1" :
790:    ret;
791:  }
792:
793:  // Make sure we're using the right name for getting the float value
794:  if ( name.match( /float/i ) ) // 正しく float セレクタ名があれば
     // jquery.js では W3C 準拠表現の cssFloat も IE 固有の styleFloat も共に
     // styleFloat で統一して扱っています。( #3210 )
795:   name = styleFloat;
796:
    // force == false で style と style.name があれば style.name 値をそのまま使用する
    // つまりブラウザによる算出スタイル値を使わずに、スタイル属性の設定値を利用する。
    // 裏返せば force=="true" ならば、style 属性の有無に拘わらず、カレントスタイル値を算出する。
797:  if ( !force && style && style[ name ] )
798:   ret = style[ name ];
    // 以下はブラウザによる描画値を取得するためのコード
    // force を指定することによりブラウザの算出描画値を取得する。
799:  // getComputedStyle 関数があれば( つまり IE 以外 )
800:  else if ( defaultView.getComputedStyle ) {
801:
802:   // Only "float" is needed here  // float 文字列が name に含まれる場合、
803:   if ( name.match( /float/i ) )
804:    name = "float"; // 使用する呼称は「 float 」だけでよい。
805:   // 所謂駱駝文字列内の大文字を小文字化してハイフンを前に付ける。
     // Javascript スタイル属性表現を CSS スタイル表現に変える。
806:   name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase();
807:   // elem 要素の描画値を取得する準備。
808:   var computedStyle = defaultView.getComputedStyle( elem, null );
809:
810:   if ( computedStyle ) // computedStyle があれば値を取得する。
      // その値をretに代入する。これによりブラウザによる描画値が ret に代入される。
811:    ret = computedStyle.getPropertyValue( name );
812:
813:   // We should always get a number back from opacity
814:   if ( name == "opacity" && ret == "" )
815:    ret = "1";
816:   // 以下は #842 迄 IE の場合
817:  } else if ( elem.currentStyle ) {
818:   var camelCase = name.replace(/\-(\w)/g, function(all, letter){
819:    return letter.toUpperCase(); // 駱駝文字列への変換を行う。
820:   });
821:   // 値を取得する。
822:   ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];
823:
824:   // From the awesome hack by Dean Edwards
825:   // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
826:
827:   // If we're not dealing with a regular pixel number
828:   // but a number that has a weird ending, we need to convert it to pixels
     // #822 の取得値 ret が数字始まりで "px" が途中にあるか、ない場合には、
829:   if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
830:    // Remember the original values
831:    var left = style.left, rsLeft = elem.runtimeStyle.left;
832:
833:    // Put in the new values to get a computed value out
      // left 値を取得してランタイムスタイルの left 値に代入し、
834:    elem.runtimeStyle.left = elem.currentStyle.left;
835:    style.left = ret || 0; // style.left 値には #822 の値を入れておき、
836:    ret = style.pixelLeft + "px"; // ret 値は正しい値を取得して代入する。
837:
838:    // Revert the changed values // 元の値を戻す。
839:    style.left = left;
840:    elem.runtimeStyle.left = rsLeft;
841:   }
842:  }
843:
844:  return ret; // ret 値を返す。
845: },
846:

 

■ コメントの投稿 ■

管理者にだけ表示を許可する

●トラックバック●

■トラックバックURLはこちら■
http://hkom.blog1.fc2.com/tb.php/696-08d192b9

●参照元一覧●

<provided Fc2>
<provided i2i>

▲ToTop

 90%近いシェアを握っているインターネットエクスプローラの描画エンジンを利用したタブbrowser。沢山のタブbrowserがあるが、多機能、カスタマイズフリー、スクリプト利用等で一日の長がある。Gekkoエンジンへの対応も行われ、IEからの自立独立の方向に向かっている。2005年7月にはIE7が登場する見通しの中で、今後の発展が望まれる。

 多様なCSS作成支援機能を備えた、タグ入力式 HTML&CSS作成支援エディタ。スキンデザインもすっきりしている。テキストエディター上で作成するよりも確実で安全にタグ打ちが出来る。
文字コードを選べないのが欠点。

 StyleNote同様のタグ入力式 HTML&CSS 作成支援エディタ。長年使用してきたが現在StyleNoteに乗り換えつつある。

 クリップボード履歴情報を活用する為のソフト。画像まで履歴を取ってくれるのが嬉しい。このソフトを使わない日は絶対ない程に重宝し、愛用している。

 起動中のウィンドウの「コピーできない」説明文などの文字列を取得し、コピー可能な文字データにするツール。何かと便利。

 ストリーミングデータを保存することが出来るソフト。動画利用には不可欠なソフトだ。

 無料ながらレイヤー機能を有し、スクリプトによる拡張も可能な、sleipnir作者が提供している優れもの画像編集ソフト。

 画面キャプチャソフトと言えばこれに勝るものなし、ではないだろうか? 様々な取得方法を有しており、ブログ作成にもHomepage作成に不可欠だ。Jtrimと並んでWoodyBellsの作品。

 複数ファイルの同時編集は出来ないが、透過pngも作れる画像編集ソフト。
(以下当該サイトから抜粋)初心者にも簡単に操作が出来るフォトレタッチソフトです。多くの加工機能で画像に様々な効果を与えることができます。非常に軽快に動作するため、ストレスなく操作できます。

 Animation Gifファイルを作れる無料ソフト。

 キャプチャソフト。画面内にサイト全体が表示しきれない場合でも、これを使えば全体をキャプチャすることが出来る。

 画像処理。画像のフォーマット変換のみならず、色数やサイズ、圧縮率の変更まで一括処理できてしまう『BatchGOO!』は、大量の画像をまとめて処理したいときに大変便利なソフト。BMP, TIFF, JPEG, PCX, PNG の相互変換をはじめ、色数・サイズ・解像度の統一、JPEG圧縮率の調節など、ホームページ用の画像や携帯電話用の壁紙を揃えるのに抜群の相性を見せる。(Vectorの当該ソフト紹介頁より抜粋引用)

 名前から直ぐに想像が付くように画像のサイズを測るためのソフトだ。Homepage作成には欠かせない。2カラム、3カラムのレイアウトを行う場合に大変重宝する。

 ランチャーソフトは沢山あるが、中でもこれが一押しだ。2年以上使ってきたがその操作性には毎日満足している。これを使い始めてからデスクトップには一切のアイコンを表示することをやめてしまった。

 AdobeReader7によって、起動時間が長すぎるという長年のユーザーの不満はある程度解消した。そのためこの高速化ソフトは存在価値が低下してしまったかもしれない。AdobeReader6迄はこのソフトによる起動高速化で恩恵を受けてきた。

 IE専用が難点だが、様々なサイト内でIDやパスワードを入力するのに重宝するソフト。コンテキストメニューから簡単に起動できるのがGood! sleipnir等のIEの描画エンジンを利用しているブラウザでも使える。

 利用しているパソコンの諸元値を取得するには、このソフトがベストだ。インストール済みソフトの一覧が取得できるのも嬉しい。

 WMPは機能が豊富なだけ重い。RealPlayerも同様だ。そこでMedia Player Classicを使いたい。動作が軽快なだけではなく、対応しているファイル形式もすこぶる多く、これひとつで、wmvもrmも表示できてしまうのだから凄い! 数多あるMedia Playerの王様と言えるだろう。

 自宅でPCを起動しているときには必ず起動しているメディアプレーヤー。何かと過剰なWinampよりも、起動も速くスキンはシンプルだ。

 DivX, Xvid, Mov, Vob, Mpeg, Mpeg4, avi, wmv, dv, などの動画をDVD-Video形式に変換できるフリーソフト。クリックするとDVD関連ソフト紹介サイト=「DVDなToolたち」なるHomepageが開きます。

----------
200903120123
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。