こんなケースを想定してみる
ページの検索フォームに入力して検索ボタンをクリックすると AJAX で検索用 API を実行する。この時に、検索パラメータを URL のクエリパラメータとして URL へ反映することはできるのか?
また、ブラウザでの戻る、進むをクリックした時も、検索結果をページに表示するのはもちろん、 URL クエリ引数や検索フォームに検索キーワードを反映させたい。
実装方法まとめ
以下、 Vue.js 2 (Options API) での勘所です。 Compotision API でもポイントは同じで、メソッドを適宜置き換えてください。どちらの実装例も本記事にあるので、具体例を参考にするのも、良いと思います。
- ページ初回表示時は
created
メソッド内でリソースサーバからデータ取得を行う。 - 検索ボタンをクリックしたら自分のページへ URL クエリ引数つきで Vue Router の
push
を行う。例えばthis.$router.push({ name: "AboutA, query: { base: "JPY" } })
となる。これによりbeforeRouteUpdate
メソッドが実行され、ここでリソースサーバからデータ取得を行う。 - リソースサーバからデータ取得を行う処理 (メソッド) では次を気をつけると良い。
- 引数として、クエリパラメータを受け取る。
- メインの処理 (リソースサーバからのデータ取得) 以外に、検索フォームへ対応する URL クエリ引数の値を設定する、などの処理を行う。
読むべき公式ページ
これらの Vue Router の公式ページをしっかりと読み込んで理解できれば、本ページでやりたいことは実現できました。
コード例
Options API
<template>
<div class="about">
<h1>This is an about page</h1>
<input v-model="paramUserId" />
<button type="button" @click="pushRouter">get</button>
<p>{{ exchangeRates }}</p>
</div>
</template>
<script>
export default {
name: "About",
async beforeRouteUpdate(to, from, next) {
// ブラウザバック時、 router.push 時にここに来る
await this.getData(to.query);
next();
},
data: () => ({
exchangeRates: {},
paramUserId: "",
}),
created() {
this.getData(this.$route.query);
},
methods: {
async getData(query) {
// 検索フォーム等へ URL クエリ引数を設定
this.paramUserId = query?.userId ?? "";
const baseUrl = "https://jsonplaceholder.typicode.com/posts";
const params = new URLSearchParams(query);
const url = `${baseUrl}?${params}`;
console.log(url);
const response = await fetch(url).then((resp) => resp.json());
this.exchangeRates = { ...response };
},
pushRouter() {
const query = {};
if (this.paramUserId) {
query.userId = this.paramUserId;
}
this.$router.push({ name: "About", query });
},
},
};
</script>
Composition API
<template>
<div class="about">
<h1>This is an about page</h1>
<input v-model="paramUserId" />
<button type="button" @click="pushRouter">get</button>
<p>{{ exchangeRates }}</p>
</div>
</template>
<script>
import { defineComponent, onMounted, ref } from "vue";
import { onBeforeRouteUpdate, useRouter, useRoute } from "vue-router";
export default defineComponent({
name: "About",
setup() {
const router = useRouter();
const route = useRoute();
const exchangeRates = ref([]);
const paramUserId = ref("");
onBeforeRouteUpdate((to) => {
// ブラウザバック時、 router.push 時にここに来る
getData(to.query);
});
const getData = async (query) => {
// 検索フォーム等へ URL クエリ引数を設定
paramUserId.value = query?.userId ?? "";
const baseUrl = "https://jsonplaceholder.typicode.com/posts";
const params = new URLSearchParams(query);
const url = `${baseUrl}?${params}`;
const response = await fetch(url).then((resp) => resp.json());
exchangeRates.value = response;
};
onMounted(getData(route.query));
const pushRouter = () => {
const query = {};
if (paramUserId.value !== "") {
query.userId = paramUserId.value;
}
router.push({ name: "About", query });
};
return {
exchangeRates,
paramUserId,
pushRouter,
};
},
});
</script>
おわりに
実際に使ったリソースサーバ、 API は次です。
Exchange Rates API- JSONPlaceholder – Free Fake REST API
- ここから選んだ。 → 【随時更新】一風変わったWeb APIをまとめてみた – Qiita
Exchange Rates API は開発中にサービスの形態が変わったのか、試行回数の上限に達したのか、途中から登録が必要となってしまいました。 それで Vue.js 3 options API 版を今回書きました。けれども、本当は Vue.js 3 Compotision API 版も書きたかったのですが、できませんでした。また別の登録不要で検索にも対応した良さそうな API があれば、試してみようと思います。
後日追記。制限がなさそうな API へと変更しました。
以上です。