2011年1月8日土曜日

jQueryのcssメソッドを拡張してみる

jQueryを使っていて気がついたことに,ベンダー独自実装のスタイルの設定があまりにも面倒なことがある.例えば「box-shadow」を例に挙げると,設定したい値はどのブラウザでも一緒なのにキーとするスタイル名称が「box-shadow」「-mox-box-shadow」「-webkit-box-shadow」「-o-box-shadow」「-ms-box-shadow」と途端に5つ設定が必要になってしまう.まぁ,css3に本格対応した際にはすべて標準名称に統一されるんだろうけれども.

そうはいっても面倒は面倒なので,jQueryの機能を拡張してcss3標準の名称を使ってスタイル値の設定を行えるようにしてみた.参考にしたのはこの記事.なるほど,styleオブジェクトがスタイルに対応するプロパティを持っているかどうかで判定できるのか!
こうすることで,例えば$("#hoge").css("border-radius", "5px")という処理をさせると自動的にfirefoxなら-moz-border-radiusに値5pxが,google cromeなら-webkit-border-radiusに値5pxが設定されるという寸法.

ブラウザが実装していないスタイルは相変わらず使えないものの,クロスブラウザ実装が簡単になる他,応用範囲は広いんじゃないか.参考にした記事では独自のパラメータを作ってますし.
//jQuery 1.4.4
(function(jQuery){
//cssメソッドを拡張する処理
(function(){

  //ベンダー接頭辞が付いている(と思われる)スタイル群
  var cssNames = [
      "background-clip",
      "background-origin",
      "background-size",
      "border-radius",
      "border-top-left-radius",
      "border-top-right-radius",
      "border-bottom-left-radius",
      "border-bottom-right-radius",
      "border-image",
      "border-image-source",
      "border-image-slice",
      "border-image-width",
      "border-image-outset",
      "border-image-repeat",
      "border-decoration-break",
      "box-shadow",
      "background-break",
      "border-break",
      "transform",
      "transform-origin",
      "column-count",
      "column-width",
      "column-gap",
      "column-rule",
      "column-rule-style",
      "column-rule-width",
      "box-sizing"
  ];

  //スタイル名称のマッピングをしておく.
  var camelNameMap = {};
  var venderCssNameMap = {};
  var appendName = function(cssName){
      //jQuery.camelCaseはスタイルの名称をelement.styleのプロパティ名に変換する.
      //実行例:-moz-box-shadow→MozBoxShadow
      var camelName = jQuery.camelCase(cssName);
      camelNameMap[cssName] = camelName;
      camelNameMap[camelName] = camelName;
      venderCssNameMap[camelName] = [
          jQuery.camelCase(cssName),//css3
          jQuery.camelCase("-webkit-" + cssName),//google chrome,safari,midori…
          jQuery.camelCase("-moz-" + cssName),//firefox
          jQuery.camelCase("-o-" + cssName),//opera
          jQuery.camelCase("-ms-" + cssName)//internet explorer
      ];
  };
  for(var i = 0, len = cssNames.length; i < len; i++){
      appendName(cssNames[i]);
  }

  //styleオブジェクトのプロパティを検索して,
  //nameに対応するプロパティを持っているかを検査する.
  var cache = {};
  var findStyle = function(style, name){
      var camelName = camelNameMap[name];
      if(camelName === undefined){
          return name;
      }

      var venderCssName = cache[camelName];
      if(venderCssName !== undefined){
          return venderCssName;
      }

      var venderCssNames = venderCssNameMap[camelName];
      for(var i = 0, len = venderCssNames.length; i < len; i++){
          if(style[venderCssNames[i]] !== undefined){
              venderCssName = venderCssNames[i]
              cache[camelName] = venderCssName;
              return venderCssName;
          }
      }

      //未対応.
      style[camelName] = "";
      return camelName;
  };

  //jQueryの内部関数をフックして
  //ベンダー独自のプロパティに変換するかどうかを判定させる.
  var originalStyle = jQuery.style;
  var originalCss = jQuery.css;
  jQuery.extend({
      //cssプロパティの設定時に呼び出される.
      style: function(elem, name){
          name = findStyle(elem.style, name);
          return originalStyle.apply(this, arguments);
      },
      //cssプロパティの取得時に呼び出される.
      css: function(elem, name){
          name = findStyle(elem.style, name);
          return originalCss.apply(this, arguments);
      }
  });
})();

})(jQuery);

0 件のコメント:

コメントを投稿