URLクラスを使って、クエリストリングを簡単に扱う
みなさん。こんにちは。 久しぶりの投稿となります。
今回はとある案件でURLにクエリストリングを付与したり削除したりという機能を開発していた時、URLのクエリ部分をオブジェクトにしたり、そのオブジェクトをクエリストリングに戻したりという処理がすごく面倒だったので、 クエリストリングの操作が楽になるライブラリを探していた所、JavaScript(ES6以降)標準で入っているURLクラスで簡単にいったので記事にしてみました。
今回は、チェックボックスにチェックがついたらnewKey
というパラメーターがURLに追加されるようにしようと思います。
デモ
HTML
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>URLSearchParamsを使ってみた</title>
</head>
<body>
<label>
<input type="checkbox" id="js-checkbox">
<span>クエリを付与</span>
</label>
<script src="./url-polyfill.js"></script><!-- IE11対応 -->
<script> //JSの処理 </script>
</body>
</html>
</code>
</pre>
JavaScript
const checkbox = document.getElementById('js-checkbox');
let paramsStr = window.location.search.substring(1); // window.location.searchから先頭の「?」を抜いた文字列を代入
let paramsArray = paramsStr.split('&'); // クエリストリングを「&」で分割したものを配列にする。
let paramsObject = {}; // 各キーと値のオブジェクト
let newParamsStr = '?'; // クエリストリング
if (paramsStr) {
paramsArray.forEach(function (val, i) {
let param = paramsArray[i].split('='); // キーと値を分離
paramsObject[param[0]] = param[1]; // オブジェクトのキーを作成
});
} // ここまでで、やっとオブジェクトが作成される。
function resetParamsStr() { // paramsObjectが変更された時にクエリストリングを再生成する関数
newParamsStr = '?';
let keys = Object.keys(paramsObject); // オブジェクトのキーを配列に
let lastKeyIndex = keys.length - 1; // 最後のキーのindex番号
if (keys.length) {
keys.forEach(function (key, index) {
newParamsStr += key+'='+paramsObject[key];
if (index === lastKeyIndex) { // ループの最後だったら後ろに「&」はいらないので終了
return;
}
newParamsStr += '&'; // 「&」を後ろにつける。
});
} else {
newParamsStr = ''; // キーがない(objectが空だった場合)文字列を空にする
}
history.pushState(null, null, window.location.pathname + newParamsStr + window.location.hash); // URLを変更
}
checkbox.addEventListener('change', function () { // checkboxにイベントを追加
let checked = checkbox.checked; // checkboxがチェックされているかどうか
if (checked) {
if ('newKey' in paramsObject) {
return; // 既にキーが存在していたら何もしない
}
paramsObject['newKey'] = 'newValue'; // paramsObjectにキーを追加
resetParamsStr(); // クエリストリングを再生成
} else {
if (!('newKey' in paramsObject)) {
return; // キーが存在しなかったら何もしない
}
delete paramsObject.newKey; // paramsObjectからキーを削除
resetParamsStr(); // クエリストリングを再生成
}
});
クエリストリングをオブジェクトに変換するだけでsplitで分割して、キーと値をさらに分割して...などの色んな処理を挟み、とても長くすっきりしないコードになってしまいました。
※アンカーリンクを併用する場合は、下記の順番で入れます。
「URL + クエリストリング + #アンカー」
もし、
「URL + #アンカー + クエリストリング」
という順番で入れてしまうとwindow.location.search
が取得できないようです。
これをURLクラスを使って書き換えると以下になります。
const checkbox = document.getElementById('js-checkbox');
const url = new URL(window.location.href); // 現在のURLを素としたURLクラスのインスタンスを作り、url定数に格納
checkbox.addEventListener('change', function () {
let checked = checkbox.checked;
if (checked) {
if (url.searchParams.has('newKey')) {
return;
}
url.searchParams.append('newKey', 'newValue'); // クエリパラメーターにnewKeyを追加
} else {
if (!url.searchParams.has('newKey')) {
return;
}
url.searchParams.delete('newKey'); // クエリパラメーターからnewKeyを削除
}
history.pushState(null, null, url.href); // URLを変更
});
とてもすっきりとしたコードになりました。 まず、二行目で現在のURLを素としたURLクラスのインスタンスを作り、url定数に格納します。
const url = new URL(window.location.href);
checkboxにチェックが入っていたら、下記のようにクエリパラメーターのキーを追加します。
url.searchParams.append('newKey', 'newValue');
checkboxのチェックがはずれていたら、下記のようにクエリパラメーターのキーを削除します。
url.searchParams.append('newKey', 'newValue');
最後にURLを書き換えます。url.href
の中身はurl.searchParams
のキーを追加したり削除したりすることでクエリストリング部分が変化します。
history.pushState(null, null, url.href);
上のコードと比べていちいち、文字列→オブジェクト、オブジェクト→文字列と変換する手間もなくよっぽどシンプルになったかと思います。
また、URLクラスはIE11では非対応なので、IE11でも動作させたい場合は、下記のpolyfillを使ってください。 https://www.npmjs.com/package/url-polyfill
最後まで読んでいただき、ありがとうございました。