あらすじ
-
/items
と/items/edit
のようなリンクのあるサイドバーを実現したい - デフォルトでは
/items/edit
を開くと/items
もアクティブになるので困る -
vue-router
の:exact
のpropをBooleanで渡して完全一致か否かを指定する -
exact
では/items?category=プロテイン
の様にQuery Paramを指定するとアクティブにならない - 特定ページにいる場合、
:to
propに渡すpathにもquery paramを渡してあげる - 解決!!
解決コード
<template>
<v-app>
<v-navigation-drawer v-model="drawer" app>
<v-list dense nav>
<template v-for="(page, index) in pageList">
<!-- ネストしていない構造 -->
<v-list-item
v-if="typeof page.items !== 'object'"
:key="index"
:to="page.to"
:exact="page.exact"
>
<v-list-item-action>
<v-icon>{{ page.icon }}</v-icon>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title v-text="page.title" />
</v-list-item-content>
</v-list-item>
<!-- ネストしている構造 -->
<v-list-group
v-else
:key="index"
:prepend-icon="page.icon"
>
<template v-slot:activator>
<v-list-item-content>
<v-list-item-title v-text="page.title" />
</v-list-item-content>
</template>
<v-list-item
v-for="(childPage, cIndex) in page.items"
:key="cIndex"
:to="childPage.to"
:exact="childPage.exact"
>
<v-list-item-icon>
<v-icon>{{ childPage.icon }}</v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title v-text="childPage.title" />
</v-list-item-content>
</v-list-item>
</v-list-group>
</template>
</v-list>
</v-navigation-drawer>
</v-app>
</template>
<script>
export default {
computed: {
pageList () {
const route = this.$route
// NOTE: どうしてもクエリーパラメーターを使いたい場合は当該pathにいる場合にrouteからfullPathを取得して当てる
const itemsPath = route.path === '/items' ? route.fullPath : '/items'
return [
// ホームはexactをtrueにしなくても問題無い
{
icon: 'home',
title: 'ホーム',
to: '/',
exact: true,
},
{
icon: 'shopping_cart',
title: '商品',
// `/items/`以下に反応されたら困るのでexactをfalse
// NOTE: しかし、このままだとクエリーパラメーターを使えない
items: [
{
title: '商品一覧',
// to: '/items'
to: itemsPath,
exact: true,
},
// 新規と編集の両方を許可したいのでexacrtはfalse
{
title: '商品登録',
to: '/items/edit',
exact: false,
},
]
},
]
}
}
}
</script>
解説
デフォルトでは/items/editを開くと/itemsもアクティブになるので困る
vue-touterはデフォルトでは部分一致でアクティブの判定をしてしまいます。
/items
と/items/edit
のような構造のpathがある場合はexact
で完全一致でアクティブ判定をするように指定してあげます。
この時、exactはBooleanで指定できるので
完全一致にしたいものだけexactをtrueにしていしてあげる事もできます。
<v-list-item
v-if="typeof page.items !== 'object'"
:key="index"
:to="page.to"
:exact="page.exact"
>
exact(完全一致)ではQuery Stringを指定するとアクティブにならない
exactでは/items?category=プロテインのようにQuery Stringを指定するとアクティブにならない
GitHubのissuesなどで色々漁った結果、公式で対応する予定は無さそうな雰囲気がしたので無理やり対応してみます。
特定ページにいる場合、クエリーも渡す
参考
How do I style an active route that has query params? - by stackoverflow
ちょっと強引な解決方法になりますが、もし他にいい方法が有ればコメントで教えて下さい!!
<script>
export default {
computed: {
pageList () {
const route = this.$route
// NOTE: どうしてもクエリーパラメーターを使いたい場合は当該pathにいる場合にrouteからfullPathを取得して当てる
const itemsPath = route.path === '/items' ? route.fullPath : '/items'
return [{
icon: 'shopping_cart',
title: '商品一覧',
to: itemsPath,
exact: true,
}]
}
}
}
</script>