URLの「?
」以降のクエリー文字列は、CGIの引数でよく用いられます。しかし、CGIはサーバー側の処理が必要で、HTMLファイルのみで完結しません。
サーバー側のプログラムを書かずに、HTMLだけで処理を完結させたいことは、時々あります。そうした時に、クエリー文字列をJavaScriptのオブジェクト化して取り出したり、その逆を行ったりできると便利です。この関数では、そうした処理を手軽に行います。
たとえばゲームの棋譜的な手順をクエリー文字列として保存しておき、そのデータを用いて途中から再開するなどして、利用できます。
ファイル構成は以下の通りです。>>ダウンロード
※ 初期化用関数「init」の処理については「Webブラウザ/Node.js 互換関数」をご覧下さい。Node.js用の処理は、今回のコードにはありません。
'use strict';
(function() {
const _t = init('com.crocro.util');
// queryToObj | クエリーをオブジェクトに
_t.queryToObj = function() {
// 変数の初期化
const obj = {};
// クエリー文字列があるなら生成
if (location.search.length > 1) {
const qArr = location.search.substr(1).split('&');
qArr.forEach(x => {
// 分割
const kvArr = x.split('=');
if (kvArr.length < 2) {return}
// オブジェクトに格納
const key = kvArr[0];
const val = decodeURIComponent(kvArr[1]);
obj[key] = val;
});
}
return obj;
};
// objToQuery | オブジェクトをクエリーに
_t.objToQuery = function(obj) {
// 変数の初期化
const res = Object.keys(obj).map(x => {
return x + '=' + encodeURIComponent(obj[x]);
}).join('&');
return res;
};
// 初期化用関数
function init(p) {
return ((o, p) => {
p.split('.').forEach(k => o = o[k]||(o[k]={}));
return o})(window, p);
};
})();
まずは、「queryToObj
」です。
「location.search
」で、「?
」以降のクエリー文字列を取り出せます。この文字列は先頭に「?
」を含んでいるので、「substr(1)
」で0文字目を除いた1文字目以降を取得して、「&
」で分割して配列にしています。
この配列の各要素を「=
」で分割したあと、値の部分を「decodeURIComponent
」でデコードしています。そして、「key
」「val
」の値を元に、オブジェクトを構築して戻り値にしています。
次に、「objToQuery
」です。
「Object.keys(obj)
」で、オブジェクトのキーの配列を得て、その配列をもとに「map
」内でキーと値を「=
」で繋いだ文字列を作成していきます。その際に、値は「encodeURIComponent
」でエンコードします。
最後に、「join('&')
」として「&
」で配列を結合して、求める文字列を得ます。
サンプルでは、「location.href
」にURLを代入して、ページを遷移しています。ページを遷移せずにURLのみを書き換える場合は、HTML5で加えられた「history.pushState()
」や「history.replaceState()
」を用います(参考:ブラウザの履歴を操作する)。
「history.pushState('', '', url)
」や「history.replaceState('', '', url)
」として、第3引数に絶対URLや相対URLを入れることで、アドレスバーのURLを書き換えます。この時、「pushState
」はページ遷移の履歴を残し、「replaceState
」は履歴を残しません。
URL文字列を絶対パスで書く場合は、same origin(プロトコルとポートとホストが等しい)である必要があります。
const queryToObj = com.crocro.util.queryToObj;
const obj = queryToObj();
console.log(JSON.stringify(obj, null, ' '));
// {
// "name_1530214040495": "あいうえお",
// "url_1530214040495": "https://crocro.com/"
// }
const objToQuery = com.crocro.util.objToQuery;
const obj = {};
obj['name_' + +new Date()] = 'あいうえお';
obj['url_' + +new Date()] = 'https://crocro.com/';
console.log(objToQuery(obj));
// name_1530214040495=%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A&url_1530214040495=https%3A%2F%2Fcrocro.com%2F
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>クエリーをオブジェクトに - JavaScript実用サンプルコード解説付き</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js">
</script>
<script src="queryToObj.js"></script>
<script src="main.js"></script>
<link rel="stylesheet" href="main.css">
</head>
<body>
<textarea id="src" style="height: 20em;"></textarea>
<button id="exec">実行</button>
<button id="reset">リセット</button>
<textarea id="dst" style="height: 8em;"></textarea>
</body>
</html>
'use strict';
$(function() {
// 変数の初期化
const $src = $('#src');
const $dst = $('#dst');
const $exec = $('#exec');
const $reset = $('#reset');
// 値のセット
$src.val(String.raw`
/*
↓URL
${location.href}
*/
const queryToObj = com.crocro.util.queryToObj;
const objToQuery = com.crocro.util.objToQuery;
// クエリーをオブジェクトにして取得
const obj = queryToObj();
// 値を追加
obj['name_' + +new Date()] = 'あいう';
obj['url_' + +new Date()] = 'https://crocro.com/';
// ページを遷移
location.href = '?' + objToQuery(obj);
`.trim());
// コンソール ログのラップ
const log = console.log;
console.log = function() {
for (let i = 0; i < arguments.length; i ++) {
$dst.append(arguments[i] + ' ');
}
$dst.append('\n');
log.apply(console, arguments);
};
// クエリー文字列を出力
const queryToObj = com.crocro.util.queryToObj;
const obj = queryToObj();
console.log(JSON.stringify(obj, null, ' '));
// クリック時の処理
$exec.click(() => {
$dst.empty();
eval($src.val());
});
$reset.click(() => {
location.href = '.';
});
});
html,
body {
margin: 0;
padding: 0;
}
textarea,
button {
box-sizing: border-box;
width: 100%;
vertical-align:bottom;
}
textarea {
height: 5em;
}