Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | <template>
<!-- 親から v-model で開閉を制御 -->
<v-navigation-drawer
v-model="localOpen"
location="left"
temporary
:width="drawerWidth"
class="drawer-overlay"
>
<!-- ヘッダーと高さを合わせたドロワ用ツールバー -->
<v-toolbar
density="comfortable"
color="transparent"
flat
class="px-2"
>
<v-btn
icon="mdi-close"
variant="text"
aria-label="Close navigation"
@click="closeOnNavigate && close()"
/>
<v-spacer />
</v-toolbar>
<v-list
density="compact"
nav
class="nav-tight"
>
<v-list-item
v-for="(link, i) in links"
:key="i"
:to="link.to"
exact
@click="closeOnNavigate && close()"
>
<template #prepend>
<v-icon size="18" class="me-0">{{ link.icon || 'mdi-circle-small' }}</v-icon>
</template>
<v-list-item-title>{{ t(link.titleKey) }}</v-list-item-title>
</v-list-item>
</v-list>
</v-navigation-drawer>
</template>
<script setup lang="ts">
// region Dependency Injection
import {computed} from 'vue'
import type {RouteLocationRaw} from 'vue-router'
import {useDisplay} from 'vuetify'
import { useI18n } from "vue-i18n";
// endregion Dependency Injection
// region Component Injection
type MenuLink = {
to: RouteLocationRaw
titleKey: string
icon?: string
}
// endregion Component Injection
// region interface
// endregion interface
// region constants
const display = useDisplay()
const { t } = useI18n()
// endregion constants
// region props
const props = defineProps<{
modelValue: boolean
links: MenuLink[]
closeOnNavigate?: boolean
}>()
// endregion props
// region variable
// endregion variable
// region properties
// スマホ (smAndDown) のときは画面幅いっぱい、それ以外は固定幅
const drawerWidth = computed(() =>
display.smAndDown.value ? '100%' : 280
)
// endregion properties
// region emits
const emit = defineEmits<{
(e: 'update:modelValue', v: boolean): void
}>()
// endregion emits
// region validator
// endregion validator
// region methods
const localOpen = computed({
get: () => props.modelValue,
set: (v: boolean) => emit('update:modelValue', v),
})
const close = () => emit('update:modelValue', false)
// endregion methods
// region export
// endregion export
</script>
<style scoped>
/* v-app-bar より前面に(必要な場合だけ) */
.nav-on-top { z-index: 2500; } /* app-barが~2000前後なので十分上 */
.drawer-overlay {
z-index: 2501 !important; /* app-bar(≈2000) より前面へ */
--v-layout-top: 0 !important; /* ヘッダぶんの top オフセットを無効化 */
top: 0 !important; /* 念のため固定 */
height: 100vh; /* 全高(スマホ時も隙間なし) */
}
</style>
|