前の記事「HTML5でモダンブラウザのCSS3バグを回避するためのハック方法」に関連して、jQuery で HTML5 データ属性にユーザーエジェント文字列を格納する方法を調べていました。その結果、ちょっと整理をしておいた方が良いかなと思う点を共有したいと思います。
ご存知の方も多いと思いますが、jQuery には .data() や jQuery.data() という、DOM 要素に データ
を紐付けて記憶しておく仕組みが元々ありました。jQuery 1.4.3 からは、 API レベルでの 親和性
が考慮された形で HTML5 data-* 属性を取り込む仕様が導入されました。
HTML5 時代では、クライアント・サイドで実行されるコード量も増え、データ属性を扱う機会もちょくちょく出てくるのではないでしょうか。そこで今回は、
- HTML5 data-* 属性のおさらい
- jQuery Data API の経緯
- jQuery Data API と HTML5 data-* 属性の共通点と違いまとめ
といった順にまとめておきたいと思います。
1.HTML5 data-* 属性のおさらい
W3C ドラフト で、ポイントとなる仕様は次の2つでしょう。
data-*属性は HTML 要素中のidやtitle、classといったグローバル属性中の、カスタム属性に位置づけられます。従って
に使える文字は HTML 要素の定義に準じます。(注)*- JavaScript から DOM 要素を通してアクセスする方法は次の2通りです。
- Attribute 関連の関数によるアクセス :
getAttribute()、setAttribute()、hasAttribute()等に、属性名をそのまま文字列として指定します。 datasetIDL 属性 によるアクセス : 先頭の
を取り除き、data-
(ハイフン)で分割した単語をキャメル・ケース化(2つ目以降の単語の先頭文字を大文字に)してつなげ、-datasetの子要素としてアクセスします。
- Attribute 関連の関数によるアクセス :
注 : 正確には
(セミコロン)と英大文字を除く XML-compatible、かつ最初の3文字が :
であってはならないというのが定義です。xmlXML-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'
もしコピーされたキャッシュではなく、元のデータ属性自体にアクセスしたいのであれば、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 data-* | jQuery Data API | |
|---|---|---|
| 紐付けの対象 | HTML 要素 | DOM 要素 |
| データの格納先 | HTML (DOM) 要素 | jQuery 内部 |
| データの形式 | 文字列 | オブジェクト |
属性名の命名規則について
HTML5 データ属性名にどんな文字が使えるか、幾つかのパターンを試してみました。その結果、混乱をなくすためには
アルファベット小文字で始まり、アルファベット小文字と数字からなる文字列を
-(ハイフン) でつなげる
がよろしいかと思います (要は、小文字の変数名をハイフンでつなげるって感じ)。
参考までに jsdo.it で試したスクリプト を置いておきます。あるタグに W3C の定義に則った data-* カスタム属性を定義し、それぞれの方法で読み出します。スクリプトのいい加減さは、ご勘弁を。
参考情報
- Embedding custom non-visible data with the data-* attributes
- W3C の HTML5 data-* 属性のドラフトです。
- .data() – jQuery API
- jQuery Data API のマニュアルです。
- jQuery.data() – jQuery API
- jQuery Data API のマニュアルです。
.data()に対しては、下位関数の位置づけですが、その分高速に動作します。
- jQuery Data API のマニュアルです。
- 2011年9月2日 Using jQuery’s Data APIs
- jQuery Data API と HTML5 data-* 属性の違いや
混乱を防ぐためのシンプルなルール
を解説してくれています。
- jQuery Data API と HTML5 data-* 属性の違いや
- 2011年2月22日 jQuery を使用し、DOM に基づいてデータを格納、取得する
- 私のこのエントリーがなくても、コレを読めば全てわかる、ってぐらいの記事です。
ピンバック: blog_cync.jp » Blog Archive » Daily Log for September 7th - thinking a sight better,
ピンバック: [jQuery][HTML5]タグに独自属性を追加した場合の扱い方 | 大発見 | 大発見
IE9で試すと以下のようになってしまいます
alert(typeof document.getElementById(‘test’).dataset); // undefined
datasetはieだと使えないのでしょうか?
@cyokodogさん、
今すぐIEを試す環境にいないので、アレですが、Can I use dataset & data-* attributes によると、IE9 で dataset は使えないのかもしれません。
HTML5 Demo: data-* あたりで、実際に試してみては如何でしょうか。
あと、jsdo.it のコード も、トラップしておくべきでしたネ。
ピンバック: jQuery HTML での data 属性の取り扱いメモ | mixmaru's blog