Vue-Routerもv4へバージョンアップしたようなので、v3とv4の書き方の比較を交えながら、Laravel9/Vue3環境でVue-Router4のインストール&設定、useRoute、useRouter、scrollBehaviorの使い方について確認する。
目次
開発環境
Windows10
Docker Desktop
WSL2
Laravel9
Laravel Sail
Vue3.2.40
Vue-Router4のインストール&設定
Vue-Router4インストール
$ sail npm install vue-router@4
router.js
import { createRouter, createWebHistory } from 'vue-router'
const BASE_URL = '/app'
import Home from './components/Home.vue'
import About from './components/About.vue'
import Item from './components/Item.vue'
import NotFound from './components/404.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home,
},
{
path: '/about',
name: 'About',
component: About,
},
{
path: '/item/:id(\\d+)',
name: 'Item',
component: Item,
},
{
path: '/404',
name: '404-NotFound',
component: NotFound,
},
{
path: '/:pathMatch(.*)',
redirect: '/404',
},
]
const router = createRouter({
history: createWebHistory(BASE_URL), // set BASE_URL
routes
})
export default router
すべてをキャッチするにはv3では「path: ‘/‘」だったがv4では「path: ‘/:pathMatch(.)’」
path: '/*',
redirect: '/404',
↓
path: '/:pathMatch(.*)',
redirect: '/404',
app.js
import './bootstrap';
import router from './router' // 追記
import { createApp } from 'vue'
import App from './components/App.vue'
const app = createApp(App)
app.use(router) // 追記
app.mount("#app")
App.vue
<main>
<router-view></router-view>
</main>
現在のルート情報の取得(useRoute)
v3ではthis.$routeで取得できたがv4ではuseRoute関数を使用してpath、name、params、query、hashなど現在のルート情報を取得。
<template>
<h1>useRoute</h1>
<p>path: {{ route.path }}</p>
<p>name: {{ route.name }}</p>
<p>params: {{ route.params }}</p>
<p>query: {{ route.query }}</p>
<p>hash: {{ route.hash }}</p>
<p>{{ message }}</p>
</template>
<script setup>
import { ref, onMounted, watch } from 'vue';
import { useRoute } from 'vue-router'
const route = useRoute()
</script>
同一コンポーネントへの遷移
同一コンポーネントへの遷移において、onMounted()などは一度しか呼び出されないので、routeを監視して変化があれば更新してやる必要がある。
<script setup>
import { reactive, onMounted, watch } from 'vue';
import { useRoute } from 'vue-router'
const route = useRoute()
const item = reactive(null)
onMounted(() => {
item = getItem()
})
const getItem = () => {
axios.get…
}
watch(route, () => {
item = getItem()
})
</script>
遷移前のRoute情報取得
computed()で取得したRoute名をwatch()で監視
<script setup>
import { ref, computed, watch } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
// 遷移前のRoute名
const prevRouteName = ref('')
// Route名の取得
const routeName = computed(() => {
return route.name
})
// Route履歴の監視
watch(routeName, (now, prev) => {
prevRouteName.value = prev
})
</script>
VueRouterのインスタンスを取得(useRouter)
v3ではthis.$routerで取得できたが、v4ではuseRouter関数を使用。
例)プログラムによる遷移
import { useRouter } from 'vue-router'
const router = useRouter()
const toItemPage = () => {
router.push({
path: '/item',
name: 'Item',
params: { id: 123 },
query: { type: 'sample' },
hash: '#abc'
})
}
/item/123?type=sample#abc
スクロール位置制御(scrollBehavior)
・同一コンポーネントへの遷移時には常にページトップにスクロールしたい。
・hashが設定されたリンクへの遷移ではhash位置(アンカーリンク)までスクロールしなければならない。
このようなスクロール位置制御はscrollBehavior関数を利用する。
const router = createRouter({
history: createWebHistory(BASE_URL), // set BASE_URL
routes,
scrollBehavior(to, from, savedPosition) {
if (to.hash) {
return {
el: to.hash,
behavior: 'smooth' // スムーズにスクロール
}
} else
if (savedPosition) {
return savedPosition
} else {
return {
top: 0
}
}
},
})
スクロール位置の設定
v3では縦横軸がx、yだったのに対してv4ではtop、leftに変更されている模様。
return { x: 0, y: 0 }
↓
return { top: 0, left: 0 }
ページ内リンク(アンカーリンク)へのスクロールではヘッダー部等のオフセットが無視されるので、別途設定が必要。
if (to.hash) {
return {
el: to.hash,
top: 60, // 追記
behavior: 'smooth'
}
}
※ページ内アンカーリンクでリロード時にヘッダー部等のオフセットが復元されない問題があった。
scrollBehaviorとvue-scrolltoとの併用
リロード時のオフセット復元の問題もいずれ修正されると思うが、それまではvue-scrolltoを使用する。
vue-scrolltoのインストール
$ sail npm install vue-scrollto
app.js
import VueScrollTo from 'vue-scrollto'
const app = createApp(App)
app.use(VueScrollTo, {
offset: -60, // オフセットも設定できる
})
app.mount("#app")
router.js
import VueScrollTo from 'vue-scrollto'
…
const router = createRouter({
history: createWebHistory(),
routes,
scrollBehavior(to, from, savedPosition) {
if (to.hash) {
VueScrollTo.scrollTo(to.hash)
return {}
} else if (savedPosition) {
return savedPosition
} else {
VueScrollTo.scrollTo('#app')
return {}
}
},
})
export default router