Edited at

Vue-router を使ったときに URL は変わったのに画面に反映されないとき

More than 1 year has passed since last update.


環境

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