q-page shows under q-header
-
MainLayout.vue
<template>
<q-layout view=“lHh lpR lFf”>
<q-header reveal elevated class=“mobile-only”>
</q-header>
<q-header class=“mobile-hide”>
</q-header>
<q-drawer
</q-drawer>
<q-page-container>
<router-view />
</q-page-container>
<q-footer elevated class=“mobile-only”>
</q-footer>
</q-layout>
</template>Page.vue
<template>
<q-page padding>
<p>This content is under the q-header on mobile. Why?</p>
</q-page>
</template> -
You have a typo in <q-drawer> tag, miss closing “>”
-
Sorry, it was accidentally omitted the closing “>” on this post, but I do have it in the acutal page. So, assuming my closing tags are all properly set, my question remains… why does the content of q-page-container start UNDER the q-header on MOBILE-HIDE and works perfectly for q-header on MOBILE-HIDE?
-
You meant that you haven’t any drawer in mobile?
-
No, drawer works perfectly in mobile. What I’m saying is that this content: <p>This content is under the q-header on mobile. Why?</p> is not visible because it is covered by the <q-header> on mobile. To see the content, I added this: <div style=“height:50px;” class=“mobile-only” /> to move the <p> 50 pixels lower to show below the <q-header>. Shouldn’t ALL of the content in the Page.vue file be seen just below the header and NOT have the header covering it up? It works correctly in desktop – content actually begins below the <q-header>, but mobile it is hidden.
-
@qwedia Have you found a solution to this issue? I’m having the same problem.
-
@Hamid Do you make sure that your page component is wrapped in a
<q-page>
tag? -
<template> <q-page class="q-pa-md"> <q-header elevated class="bg-yellow"> <q-toolbar> <q-btn flat round dense icon="arrow_back_ios" text-color="grey" class="q-mr-sm" @click="$router.go(-1)"/> <q-toolbar-title class="text-grey text-center text-bold">Options</q-toolbar-title> <q-btn flat round/> </q-toolbar> </q-header> <h6 class="text-bold text-grey">{{surah.name_simple}}</h6> <q-list bordered separator class="surah-list"> <q-item clickable v-ripple @click="$router.push({ name: 'select-aya-from', params: { surah: surah } })"> <q-item-section> <q-item-label>Aya from</q-item-label> </q-item-section> </q-item> <q-item clickable v-ripple @click="$router.push({ name: 'select-aya-to', params: { surah: surah } })"> <q-item-section> <q-item-label>Aya to</q-item-label> </q-item-section> </q-item> </q-list> </q-page> </template>
The q-header is inside the q-page.
One thing to note is that it only happens if I’m using keep-alive on router-view and only when you navigate back to the page which has the q-header.
The problem doesn’t occur on the first page load but if you navigate away and then back, you will see that they q-page is underneath q-header. -
@Hamid Your q-header should be a direct child of q-layout. There’s two good options to doing this.
First option
Use vue-router named views. In this case, you separate the page body and header into
settings-page.vue
(root tag is q-page) andsettings-header.vue
(root tag is q-header). In your routes file, something like this:const router = new VueRouter({ routes: [ { path: '/settings', components: { default: () => import('pages/settings-page.vue'), header: () => import('pages/settings-header.vue'), } } ] })
and in MainLayout.vue:
<template> <q-layout view="lHh Lpr lFf"> <router-view name="header" /> <q-drawer> ... </q-drawer> <q-page-container> <router-view /> </q-page-container> </q-layout> </template>
That will inject the settings-header.vue component into the first router-view and the page into the second router-view. This way you can make different headers, or no header at all, based on the route.
Read more: https://router.vuejs.org/guide/essentials/named-views.html
Second option
Use vue-portal. In this case, you keep the q-header in your current component, but wrap it in a portal tag. In your settings component, it would look like this:
<template> <q-page class="q-pa-md"> <portal to="header"> <q-header elevated class="bg-yellow"> <q-toolbar> <q-btn flat round dense icon="arrow_back_ios" text-color="grey" class="q-mr-sm" @click="$router.go(-1)"/> <q-toolbar-title class="text-grey text-center text-bold">Options</q-toolbar-title> <q-btn flat round/> </q-toolbar> </q-header> </portal> <h6 class="text-bold text-grey">{{surah.name_simple}}</h6> <q-list bordered separator class="surah-list"> .... </q-list> </q-page> </template>
And in main layout:
<template> <q-layout view="lHh Lpr lFf"> <portal-target name="header"></portal-target> <q-drawer> ... </q-drawer> <q-page-container> <router-view /> </q-page-container> </q-layout> </template>
For this, you must install with
yarn add portal-vue
then make a boot file atsrc/boot/portal.js
with contents:import PortalVue from 'portal-vue' export default({ Vue }) => { Vue.use(PortalVue) }
And make sure to add
'portal'
to the boot array in quasar.conf.jsRead more: https://github.com/LinusBorg/portal-vue
For your case, I probably recommend the first option as it is built in to vue-router. I would recommend the second case if the header needed to call methods of the page, or share data that you don’t want in vuex, etc.