環境
vue v2.5.13
vue-router v3.0.1
ハマったこと
/#/items/aaa
画面内で /#/items/bbb
へ遷移しようとすると、ブラウザの URL は切り替わるけど画面の View が反映されない。
元々実装していたソースコード
必要なとこだけ。...
のとこは省略。
/#/items/aaa
ページ内に items
のリストリンクを表示して、 ページ内から /#/items/bbb
へ遷移させる CRUD 画面あるあるの UI。
src/app.js
import Vue from "vue";
import router from "./router";
const vm = new Vue({
el: "#app",
router
});
export default vm;
src/router.js
import Vue from "vue";
import VueRouter from "vue-router";
Vue.use(VueRouter);
const routes = [
{
name: "top",
path: "/",
component: require("../container/top.vue")
},
{
path: "/items",
component: require("../container/items-list.vue")
},
{
path: "/items/:id",
component: require("../container/items-detail.vue")
},
...
{
path: "*",
redirect: {name: "top"},
}
];
const router = new VueRouter({
routes
});
export default router;
src/conainer/items-detail.vue
<template>
...
<items-detail :id="$route.params.id"></items-detail>
<items-pickup></items-pickup>
...
</template>
<script>
import itemsDetail from "../components/items-detail.vue";
import itemsPickup from "../components/items-pickup.vue";
...
export default {
created() {
...
},
data() {
return {
...
};
},
components: {
"items-detail": itemsDetail,
"items-pickup": itemsPickup,
...
}
};
</script>
src/components/items-pickup.vue
<template>
...
<router-link v-for="item in items" :to="'/items/'+item.id" tag="a">{{item.name}}</router-link>
...
</template>
<script>
export default {
created() {
...
},
data() {
return {
items: {
id: "aaa",
name: "ぺーじそのいち"
},
{
id: "bbb",
name: "ぺーじそのに"
},
{
id: "ccc",
name: "ぺーじそのさん"
}
};
}
};
</script>
解決策
Vue2.2 で追加された beforeRouteUpdate
関数を使って画面を再描画する処理を入れる。
beforeRouteUpdate
関数を使うことで、そのコンポーネントを描画するルートが変更されたときに呼び出され、新しいルートで再利用される。(※1)
変更後のソースコード
src/conainer/items-detail.vue
<template>
...
<items-detail :id="$route.params.id" ref="items"></items-detail> // 追記
<items-pickup></items-pickup>
...
</template>
<script>
import itemsDetail from "../components/items-detail.vue";
import itemsPickup from "../components/items-pickup.vue";
...
export default {
created() {
...
},
data() {
return {
...
};
},
components: {
"items-detail": itemsDetail,
"items-pickup": itemsPickup,
...
},
// 追記
beforeRouteUpdate (to, from, next) {
// URL の id が変わったときに src/components/items-detail.vue の updateItem 関数を実行してモデルを更新する
this.$refs.items.updateItem();
next();
}
};
</script>
src/components/items-detail.vue
<template>
...
</template>
<script>
export default {
created() {
...
},
props: {
id: String
},
data() {
return {
item: {}
};
},
methods: {
updateItem() {
// URL の id の値を元に紐づくデータを取得して返す関数
return getCurrentItem(this.$route.params.id);
},
...
};
</script>
Reference
※1) https://router.vuejs.org/ja/advanced/navigation-guards.html