Hatena::Diary

?D of K このページをアンテナに追加 RSSフィード

2009-09-15

ブラウザごとのlocation.hashの挙動のまとめ

今更ですが、location.hashで現在のステータスを管理するのがマイブームです。しかし、ASCII以外をぶち込むとブラウザごとに挙動が違うっぽいです。というのを調べておいて、書いておくのを忘れたので、まとめておきます。

方法

以下のアクションを起こした場合、location.hashで取得できる値がどうなるか、調べました。なお、ファイルはUTF-8で試しました。

ファイルに書いてあるリンクをクリックした場合
  • A1:#test
  • B1:#てすと
  • C1:#%E3%81%A6%E3%81%99%E3%81%A8
  • A2:#test#test
  • B2:#てすと#てすと
  • C2:#%E3%81%A6%E3%81%99%E3%81%A8#%E3%81%A6%E3%81%99%E3%81%A8
  • A3:#test%23test
  • B3:#てすと%23てすと
  • C3:#%E3%81%A6%E3%81%99%E3%81%A8%23%E3%81%A6%E3%81%99%E3%81%A8

頭が#じゃないやつの結果は見えているのでやりません。

location.hashへ代入した場合

a1〜c3まで上のテストの文字列から#を削ったものと一致します。

こいつを地道にクリックした感じです。もうちょい自動化されたやつはどっかいった。

<!doctype html>
<html>
<head><meta charset="UTF-8"></head>
<body>
<p>
<a href="#test">A1</a>
<a href="#てすと">B1</a>
<a href="#%E3%81%A6%E3%81%99%E3%81%A8">C1</a>
<a href="#test#test">A2</a>
<a href="#てすと#てすと">B2</a>
<a href="#%E3%81%A6%E3%81%99%E3%81%A8#%E3%81%A6%E3%81%99%E3%81%A8">C2</a>
<a href="#test%23test">A3</a>
<a href="#てすと%23てすと">B3</a>
<a href="#%E3%81%A6%E3%81%99%E3%81%A8%23%E3%81%A6%E3%81%99%E3%81%A8">C3</a>
</p>
<p>
<span id="a1">a1</span>
<span id="b1">b1</span>
<span id="c1">c1</span>
<span id="a2">a2</span>
<span id="b2">b2</span>
<span id="c2">c2</span>
<span id="a3">a3</span>
<span id="b3">b3</span>
<span id="c3">c3</span>
</p>
<p><input id="r"></p>
<script type="text/javascript">
function $(id) { return document.getElementById(id); }
$("a1").onclick = function () {
	location.hash = "test";
};
$("b1").onclick = function () {
	location.hash = "てすと";
};
$("c1").onclick = function () {
	location.hash = "%E3%81%A6%E3%81%99%E3%81%A8";
};
$("a2").onclick = function () {
	location.hash = "test#test";
};
$("b2").onclick = function () {
	location.hash = "てすと#てすと";
};
$("c2").onclick = function () {
	location.hash = "%E3%81%A6%E3%81%99%E3%81%A8#%E3%81%A6%E3%81%99%E3%81%A8";
};
$("a3").onclick = function () {
	location.hash = "test%23test";
};
$("b3").onclick = function () {
	location.hash = "てすと%23てすと";
};
$("c3").onclick = function () {
	location.hash = "%E3%81%A6%E3%81%99%E3%81%A8%23%E3%81%A6%E3%81%99%E3%81%A8";
};

setInterval(function () {
	$("r").value = location.hash;
}, 1000);
</script>
</body>
</html>

結果

ブラウザA1B1C1A2B2C2A3B3C3
IE6#test#てすと#%E3%81%A6%E3%81%99%E3%81%A8#test#test#てすと#てすと#%E3%81%A6%E3%81%99%E3%81%A8#%E3%81%A6%E3%81%99%E3%81%A8#test%23test#てすと%23てすと#%E3%81%A6%E3%81%99%E3%81%A8%23%E3%81%A6%E3%81%99%E3%81%A8
Fx3.5#test#てすと#てすと#test#test#てすと#てすと#てすと#てすと#test#test#てすと#てすと#てすと#てすと
Opera10#test#てすと#%E3%81%A6%E3%81%99%E3%81%A8#test#test#てすと#てすと#%E3%81%A6%E3%81%99%E3%81%A8#%E3%81%A6%E3%81%99%E3%81%A8#test%23test#てすと%23てすと#%E3%81%A6%E3%81%99%E3%81%A8%23%E3%81%A6%E3%81%99%E3%81%A8
Safari4#test#%E3%81%A6%E3%81%99%E3%81%A8#%E3%81%A6%E3%81%99%E3%81%A8#test%23test#%E3%81%A6%E3%81%99%E3%81%A8%23%E3%81%A6%E3%81%99%E3%81%A8#%E3%81%A6%E3%81%99%E3%81%A8%23%E3%81%A6%E3%81%99%E3%81%A8#test%23test#%E3%81%A6%E3%81%99%E3%81%A8%23%E3%81%A6%E3%81%99%E3%81%A8#%E3%81%A6%E3%81%99%E3%81%A8%23%E3%81%A6%E3%81%99%E3%81%A8
Chrome#test#てすと#%E3%81%A6%E3%81%99%E3%81%A8#test#test#てすと#てすと#%E3%81%A6%E3%81%99%E3%81%A8#%E3%81%A6%E3%81%99%E3%81%A8#test%23test#てすと%23てすと#%E3%81%A6%E3%81%99%E3%81%A8%23%E3%81%A6%E3%81%99%E3%81%A8

IE、Opera、Chromeは代入された値を返す。Firefoxは全てdecode、Safariは全てencodeされた結果を返す。

ブラウザa1b1b1a2b2c2a3b3c3
IE6#test#てすと#%E3%81%A6%E3%81%99%E3%81%A8#test#test#てすと#てすと#%E3%81%A6%E3%81%99%E3%81%A8#%E3%81%A6%E3%81%99%E3%81%A8#test%23test#てすと%23てすと#%E3%81%A6%E3%81%99%E3%81%A8%23%E3%81%A6%E3%81%99%E3%81%A8
Fx3.5#test#てすと#てすと#test#test#てすと#てすと#てすと#てすと#test#test#てすと#てすと#てすと#てすと
Opera10#test#てすと#%E3%81%A6%E3%81%99%E3%81%A8#test#test#てすと#てすと#%E3%81%A6%E3%81%99%E3%81%A8#%E3%81%A6%E3%81%99%E3%81%A8#test%23test#てすと%23てすと#%E3%81%A6%E3%81%99%E3%81%A8%23%E3%81%A6%E3%81%99%E3%81%A8
Safari4#test#%E3%81%A6%E3%81%99%E3%81%A8#%E3%81%A6%E3%81%99%E3%81%A8#test%23test#fYh%23fYh#%E3%81%A6%E3%81%99%E3%81%A8%23%E3%81%A6%E3%81%99%E3%81%A8#test%23test#%E3%81%A6%E3%81%99%E3%81%A8%23%E3%81%A6%E3%81%99%E3%81%A8#%E3%81%A6%E3%81%99%E3%81%A8%23%E3%81%A6%E3%81%99%E3%81%A8
Chrome#test#てすと#%E3%81%A6%E3%81%99%E3%81%A8#test#test#てすと#てすと#%E3%81%A6%E3%81%99%E3%81%A8#%E3%81%A6%E3%81%99%E3%81%A8#test%23test#てすと%23てすと#%E3%81%A6%E3%81%99%E3%81%A8%23%E3%81%A6%E3%81%99%E3%81%A8

Safariはencodeしないとバグる場合がある。

まとめ

  • アンカーを付けたリンクを生成する場合は必ずencodeURIComponentでencodeして付与する。
  • location.hashに代入する場合も必ずencodeURIComponentでencodeして代入する。
  • 以上が守られたlocation.hashの値を取得する場合はFirefox以外はdecodeURIComponentでdecodeする。

と、クロスブラウザなlocation.hashの扱いが可能になる。

おまけ

jQueryライブラリにしてあったのを思い出した。

$.anchor = function (val, skip) {
	var fn = arguments.callee;
	switch (typeof val) {
		// getter
		case "undefined":
			var ret = location.hash;
			if (!ret) {
				return null;
			}
			ret = ret.replace(/^#/, "");
			return $.browser.fx ? ret : decodeURIComponent(ret);
		// callback
		case "function":
			if (!fn.tid) {
				fn.hash = location.hash;
				(function rec() {
					if (!fn.skip && fn.hash !== location.hash) {
						fn.hash = location.hash;
						$(window).trigger("changeAnchor", $.anchor());
					}
					fn.tid = setTimeout(rec, 300);
				})();
			}
			return $(window).bind("changeAnchor", val);
		// setter
		default:
			if (skip) {
				fn.skip = true;
				location.hash = encodeURIComponent(val);
				fn.hash = location.hash;
				fn.skip = false;
			}
			else {
				location.hash = encodeURIComponent(val);
			}
			return;
	}
};

// 取得
$.anchor();
// 代入
$.anchor("てすと");
$.anchor("てすと", true); // イベントに反映させない
// location.hashが変化したら、取得
$.anchor(function (evt, hash) { alert(hash + "に変わったよ") });

なんか、ページ番号とかをlocation.hashで管理している場合は、使い道があるかもしれません。バグっているかもしれないけど。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/ofk/20090915/1252993893