URLSearchParams の基本(クエリ操作) — const p = new URLSearchParams(location.search)
URL の「?以降」のクエリを簡単に読み書きできるのが URLSearchParams。get, set, append, delete, toString で直感的に扱えます。フォームの検索条件、ページの状態共有、フィルターの保持などに便利です。
まずは読み取りの基本
<script>
// 例: https://example.com/?q=apple&page=2
const p = new URLSearchParams(location.search);
console.log(p.get("q")); // "apple"
console.log(p.get("page")); // "2"(文字列)
console.log(p.has("sort")); // false(存在チェック)
</script>
HTML- 対象:
location.searchは現在ページのクエリ文字列。これをURLSearchParamsに渡して操作します。 - 戻り値の型: すべて文字列。数値にしたい場合は
Number(...)で変換。
クエリの作成・編集(toString で反映)
// 新規に作って使う
const params = new URLSearchParams();
params.set("q", "apple"); // 置き換え(なければ追加)
params.set("page", "2");
params.append("tag", "red"); // 同キーを複数持たせたいとき(tag=red&tag=...)
params.append("tag", "fresh");
console.log(params.toString()); // "q=apple&page=2&tag=red&tag=fresh"
JavaScript- set と append の違い:
- set: そのキーの値を「1つに」する(既存があれば置き換え)。
- append: 値を「追加」する(同キー複数の列挙に向く)。
例題1: クエリで初期状態を決める(検索UI)
<input id="q" placeholder="検索語">
<select id="sort">
<option value="new">新着</option>
<option value="popular">人気</option>
</select>
<button id="apply">反映</button>
<script>
// 1) 画面読み込み時にクエリから初期値を復元
const p = new URLSearchParams(location.search);
document.getElementById("q").value = p.get("q") || "";
document.getElementById("sort").value = p.get("sort") || "new";
// 2) 「反映」ボタンでクエリを書き換えてページ更新なしで履歴追加
document.getElementById("apply").addEventListener("click", () => {
const q = document.getElementById("q").value.trim();
const sort = document.getElementById("sort").value;
const next = new URLSearchParams(location.search);
if (q) next.set("q", q); else next.delete("q");
next.set("sort", sort);
const url = `${location.pathname}?${next.toString()}${location.hash}`;
history.pushState(null, "", url); // URLだけ更新(ページは再読み込みしない)
// 必要ならここで検索処理を呼ぶ
// performSearch({ q, sort });
});
</script>
HTML- ポイント:
history.pushStateで「URLは更新、ページは保持」。戻る/進むで状態も追跡できます。
例題2: チェックボックス複数選択をクエリに保存
<label><input type="checkbox" name="tag" value="red">赤</label>
<label><input type="checkbox" name="tag" value="green">緑</label>
<label><input type="checkbox" name="tag" value="blue">青</label>
<button id="save">保存</button>
<script>
// 初期復元(?tag=red&tag=blue のような複数値)
const p = new URLSearchParams(location.search);
const selected = p.getAll("tag"); // ["red","blue"]
document.querySelectorAll('input[name="tag"]').forEach(ch => {
ch.checked = selected.includes(ch.value);
});
// 保存(複数値は append で積む)
document.getElementById("save").addEventListener("click", () => {
const next = new URLSearchParams();
document.querySelectorAll('input[name="tag"]:checked').forEach(ch => {
next.append("tag", ch.value);
});
const url = `${location.pathname}?${next.toString()}`;
history.replaceState(null, "", url); // 現在の履歴を書き換え
});
</script>
HTML- ポイント: 複数値は
getAllとappend。replaceStateは「履歴を積み増ししない更新」。
例題3: ベースURLからクエリを合成して遷移
function buildUrl(base, paramsObj) {
const url = new URL(base, location.origin);
const p = new URLSearchParams(paramsObj); // { q: "apple", page: 2 } など
url.search = p.toString();
return url.toString();
}
const link = buildUrl("/search", { q: "apple", page: 2, sort: "new" });
// "/search?q=apple&page=2&sort=new"
location.href = link; // 遷移
JavaScript- ポイント:
new URL(base, origin)を使うと絶対/相対を意識せず安全に組み立てられます。
実務でのコツ
- エンコードは任せてOK:
URLSearchParamsは自動で適切にエンコードします。生の文字列連結より安全。 - 空文字/未設定の扱い: 空なら
delete、値があるならsetのルールで一貫性を持つ。 - 型の復元: 数値や真偽値は取得後に変換。
- 例:
const page = Number(p.get("page") || 1); const debug = p.get("debug") === "1";
- 例:
- 順序の安定:
toString()の順序は追加した順が基本。テストで順序が必要なら、キー追加の順を固定する。 - URLだけ更新したい:
pushState/replaceStateでページ遷移なしにURLを更新。イベントハンドラで状態を再反映する。
ありがちなハマりポイントと対策
- 同キー複数を上書きしてしまう:
- 対策: 複数値は
append、読み取りはgetAll。
- 対策: 複数値は
location.searchを直接いじる:- 対策: 直接代入では遷移が発生しがち。合成して
history.*Stateを使うと滑らか。
- 対策: 直接代入では遷移が発生しがち。合成して
- 未定義で
Number(null)が0になる誤判定:- 対策:
p.get(...) || defaultを挟んでから変換。
- 対策:
- #hash との併用で消えてしまう:
- 対策: 既存の
location.hashを保持して URL を再構築。
- 対策: 既存の
練習問題(検索とソートのクエリを完全同期)
<input id="q" placeholder="検索語">
<select id="sort">
<option value="new">新着</option>
<option value="popular">人気</option>
</select>
<button id="apply">反映</button>
<script>
function readParams() {
const p = new URLSearchParams(location.search);
return {
q: p.get("q") || "",
sort: p.get("sort") || "new",
};
}
function writeParams({ q, sort }, push = true) {
const p = new URLSearchParams();
if (q) p.set("q", q);
p.set("sort", sort);
const url = `${location.pathname}?${p.toString()}${location.hash}`;
(push ? history.pushState : history.replaceState).call(history, null, "", url);
}
// 初期反映
const init = readParams();
q.value = init.q; sort.value = init.sort;
// 操作で反映
document.getElementById("apply").addEventListener("click", () => {
writeParams({ q: q.value.trim(), sort: sort.value }, true);
// performSearch(...); // 実検索へ
});
// 戻る/進むでフォーム状態を更新
window.addEventListener("popstate", () => {
const cur = readParams();
q.value = cur.q; sort.value = cur.sort;
// performSearch(...); // 必要なら再実行
});
const q = document.getElementById("q");
const sort = document.getElementById("sort");
</script>
HTML直感的な指針
- 読むときは
new URLSearchParams(location.search)、書くときはset/append/delete → toString()。 - URLだけ更新したいなら
history.pushState/replaceStateを併用。 - 複数値は
getAll/append、型は取得後に変換して扱う。
