意外と要注意 HTML5データ属性とjQuery Data APIの関係まとめ

前の記事「HTML5でモダンブラウザのCSS3バグを回避するためのハック方法」に関連して、jQuery で HTML5 データ属性にユーザーエジェント文字列を格納する方法を調べていました。その結果、ちょっと整理をしておいた方が良いかなと思う点を共有したいと思います。

ご存知の方も多いと思いますが、jQuery には .data()jQuery.data() という、DOM 要素に データ を紐付けて記憶しておく仕組みが元々ありました。jQuery 1.4.3 からは、 API レベルでの 親和性 が考慮された形で HTML5 data-* 属性を取り込む仕様が導入されました。

HTML5 時代では、クライアント・サイドで実行されるコード量も増え、データ属性を扱う機会もちょくちょく出てくるのではないでしょうか。そこで今回は、

  1. HTML5 data-* 属性のおさらい
  2. jQuery Data API の経緯
  3. jQuery Data API と HTML5 data-* 属性の共通点と違いまとめ

といった順にまとめておきたいと思います。

1.HTML5 data-* 属性のおさらい

W3C ドラフト で、ポイントとなる仕様は次の2つでしょう。

  • data-* 属性は HTML 要素中の idtitleclass といったグローバル属性中の、カスタム属性に位置づけられます。従って * に使える文字は HTML 要素の定義に準じます。(
  • JavaScript から DOM 要素を通してアクセスする方法は次の2通りです。
    • Attribute 関連の関数によるアクセス : getAttribute()setAttribute()hasAttribute() 等に、属性名をそのまま文字列として指定します。
    • dataset IDL 属性 によるアクセス : 先頭の data- を取り除き、-(ハイフン)で分割した単語をキャメル・ケース化(2つ目以降の単語の先頭文字を大文字に)してつなげ、dataset の子要素としてアクセスします。

注 : 正確には :(セミコロン)と英大文字を除く XML-compatible、かつ最初の3文字が xml であってはならないというのが定義です。XML-compatible な文字 とは、先頭が英文字または _(アンダースコア)で始まり、2文字目以降が -(ハイフン)と .(ピリオド)を含む英数字 (さらにいくつかの Unicode文字 を含む) です。ただし .(ピリオド)を含めてしまうと、dataset を介した際におかしくなるので、やめた方が良いでしょう。

具体例

次の様な HTML に対し、

<div id='test' data-foo-bar='hoge'></div>

データ属性にアクセスする方法は以下の通りです。

var e = document.getElementById('test');
console.log(e.getAttribute('data-foo-bar'));
console.log(e.dataset.fooBar);

う~ん、キャメル・ケース化とかややこしいですよネ。HTML 要素の定義と DOM 要素の定義の両面を満足させる、苦肉の策って感じです 😉 。

2.jQuery Data API の経緯

2008年2月7日、jQuery 1.2.3 で初めて jQuery.data() および jQuery.fn.data() が公開されました。DOM 要素に 何らかのデータ を紐付たいというニーズは昔からあったのでしょう。キーとオブジェクト (文字列、数値、配列、関数など) をペアにして、特定の DOM に紐付ることができます。そもそもは、(文法的には間違いだが) HTML 要素の何かしらの不可視属性に (文字列の) データを埋め込こんだとき、うかつに DOM を操作すると IE がメモリー・リークを起こすという不具合があったため、jQuery で DOM を操作している限りはそういった問題が起きないようにするためだったようです。

さらに jQuery 1.4.3 では、HTML5 data-* 属性の属性名をキーとして指定すると、その属性値を jQuery 内のキャッシュに オブジェクトとしてコピーする という仕様が取り入れられました。例えば

<div data-text='hoge' data-boolean='true' data-object-value='{"name":"John"}'></div>

に対し、次が成立します。

$('div').data('text') === 'hoge';
$('div').data('boolean') === true;
$('div').data('objectValue').name === 'John';
$('div').data('object-value').name === 'John'; // この書式はHTML5と違う

つまり、dataset を介してアクセスする時のルールとほぼ同じです (キャメル・ケースの仕様が正しく実装された のは jQuery 1.6 からです)。

気を付けるべきは、一旦コピーされた HTML5 データ属性は、元の値 (こちらは単なる文字列で、相変わらず HTML 要素上に存在しています) とは独立に評価され、それぞれの型を持つオブジェクトになるという点です。つまり、

<div data-value='1e3'></div>

に対しては、1e3 が浮動小数点として評価されることになります。

console.log(typeof $('div').data('value')); // 'number'

注意!

1e3number と評価されるのは jQuery 1.7.x までで、1.8 からは string のままになりました。1000 は変わらずに number と評価されますので、ご注意を 😉 。

もしコピーされたキャッシュではなく、元のデータ属性自体にアクセスしたいのであれば、jQuery.fn.attr() を使う必要があります (結果は文字列となります)。使い方は、ネイティブな関数 getAttribute()setAttribute() などと同様です。

3.jQuery Data API と HTML5 data-* 属性の共通点と違いまとめ

それぞれに都合や経緯があるのは 致し方ない ことですが、意識した上でなるべく混乱のないように使うべきです。もっとも、割り切って両者は違うものと考えるのも手ですが…。

共通点

はっきり言って HTML 要素から data-* 属性の値を読み出す時のルールだけです。

<div id='test' data-foo-bar='hoge'></div>
var i = document.getElementById('test');
var j = $('#test');
console.log(i.getAttribute('data-foo-bar'));
console.log(j.attr('data-foo-bar'));
console.log(i.dataset.fooBar);
console.log(j.data('fooBar'));

相違点

データを紐付ける対象が違うってことと、jQuery の場合、データ属性への最初のアクセス以降は、HTML (あるいは DOM) 要素とは独立に jQuery 内部にデータを格納するってところが最大のポイントだと思います。

HTML5 データ属性と jQuery Data API との相違点
HTML5 data-* jQuery Data API
紐付けの対象 HTML 要素 DOM 要素
データの格納先 HTML (DOM) 要素 jQuery 内部
データの形式 文字列 オブジェクト

属性名の命名規則について

HTML5 データ属性名にどんな文字が使えるか、幾つかのパターンを試してみました。その結果、混乱をなくすためには

アルファベット小文字で始まり、アルファベット小文字と数字からなる文字列を (ハイフン) でつなげる

がよろしいかと思います (要は、小文字の変数名をハイフンでつなげるって感じ)。

参考までに jsdo.it で試したスクリプト を置いておきます。あるタグに W3C の定義に則った data-* カスタム属性を定義し、それぞれの方法で読み出します。スクリプトのいい加減さは、ご勘弁を。

HTML5 data-* VS jQuery Data API – jsdo.it – share JavaScript, HTML5 and CSS

参考情報

意外と要注意 HTML5データ属性とjQuery Data APIの関係まとめ」への6件のフィードバック

  1. ピンバック: blog_cync.jp » Blog Archive » Daily Log for September 7th - thinking a sight better,

  2. ピンバック: [jQuery][HTML5]タグに独自属性を追加した場合の扱い方 | 大発見 | 大発見

  3. cyokodog

    IE9で試すと以下のようになってしまいます
    alert(typeof document.getElementById(‘test’).dataset); // undefined
    datasetはieだと使えないのでしょうか?

    返信
  4. ピンバック: jQuery HTML での data 属性の取り扱いメモ | mixmaru's blog

  5. ピンバック: WordPress ギャラリーを印象的に見せるレスポンシブスライダー(複数設置対応)プラグイン | セルティスラボ

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

海外からの投稿は受け付けていません