4
votes

VueJs - Comment masquer le composant global (par exemple la barre de navigation) sur certaines routes?

Ainsi, la grande majorité des vues sur ma vuejs SPA ont un composant navbar en haut. Cependant, certaines vues sélectionnées telles que la connexion ne devraient pas l'afficher.

Ma solution de contournement était d'importer la barre de navigation et de l'ajouter à chaque vue individuellement si nécessaire, mais maintenant je peux voir que cela provoque un scintillement étrange lors du passage d'une vue à une autre - probablement parce que le composant de la barre de navigation est en cours de suppression, et immédiatement rajouté . Cela semble faux.

Je suppose qu'il existe un moyen d'ajouter le composant navbar dans App.vue mais le masquer conditionnellement sur certaines routes avec vue-router? Quelle est la meilleure pratique pour cela?


0 commentaires

3 Réponses :


8
votes

La méthode courante consiste à utiliser des itinéraires imbriqués. Voici un exemple de l'un de mes projets:

<!-- Admin shell -->
<v-container fill-height>
    <v-toolbar color="blue darken-3" dark app :clipped-left="$vuetify.breakpoint.mdAndUp" fixed>
        <v-toolbar-title style="width: 300px" class="ml-0 pl-3">
            <v-toolbar-side-icon @click.stop="drawer = !drawer"></v-toolbar-side-icon>
            <span class="hidden-sm-and-down">Admin</span>
        </v-toolbar-title>
        <v-spacer></v-spacer>
        <UserInfo></UserInfo>
    </v-toolbar>

    <!-- Nested route -->
    <router-view></router-view>
</v-container>

La vue principale aura juste un composant de vue du routeur, de sorte que le composant de vue de connexion peut être affiché sans barre de navigation.

<!-- App -->
<v-app>
    <v-content>
        <router-view> </router-view>
    </v-content>
</v-app>

Le shell d'administration sera injecté dans la vue principale et contiendra la barre de navigation, la barre latérale et tout ce dont il a besoin.

const router = new Router({
    mode: 'history',
    base: process.env.BASE_URL,
    routes: [
        {
            path: '/login',
            name: 'login',
            component: LoginView,
        },
        {
            path: '/admin',
            name: 'admin',
            component: AdminShell,
            children: [
                {
                    path: 'home',
                    name: 'admin_home',
                    component: AdminHomeView
                },
            ]
        },
    ],
});

Ensuite, AdminHomeView sera injecté dans la vue du routeur imbriquée de la vue du shell d'administration.


1 commentaires

Exactement comme je le fais!



7
votes

Je préfère un composant rendu conditionnel dans la vue principale à l'approche des routes imbriquées @Edins.

Vue fournit un excellent magasin d'état global via Vuex ce qui rend cela incroyablement simple.

L'exemple classique serait de n'avoir la barre de navigation que lorsque l'utilisateur est connecté.
Vous suivez donc l'état de connexion dans le magasin d'état, puis utilisez un getter calculé dans votre vue principale (ou App.vue):

<template>
  <navbar v-if="isAuthenticated"/>
  <router-view/>
</template>

export default {
name: 'App',
computed: { 
  isAuthenticated() {
    return this.$store.getters.isAuthenticated
  },
},


3 commentaires

un problème que j'ai remarqué avec cette approche est que la barre de navigation est de nouveau rendue à chaque fois que la vue change, ce qui provoque un effet de scintillement étrange lorsque la barre de navigation disparaît pendant une fraction de seconde puis revient. Y a-t-il un moyen de résoudre ce problème?


Cette approche ne rend pas à nouveau la barre de navigation lors du changement d'itinéraire (vérifiable en enregistrant quelque chose dans les barres de navigation créées ou montées au crochet). La barre de navigation ainsi que la propriété calculée sont en dehors de la <router-view/> donc un changement de route ne peut pas entraîner un nouveau rendu. Si c'est le cas, partagez votre code afin que nous puissions essayer de vous aider à identifier le problème @danmartin


Dans mon cas, je voulais juste masquer la brand sur la page d'accueil (car elle est déjà affichée dans une section héros), alors je suis passée en accessoire au composant navbar.



2
votes

Nous pouvons rendre conditionnellement les composants en vérifiant le nom de la route actuelle à l'aide de la directive v-if. J'ai utilisé ceci dans un projet récent.

Mon fichier route index.js

<template>
    <div id="app">

/* Note that this takes an array of route names, so you can simply pass in
the name of the route you don't want this component to be displayed on */

        <navbar v-if="!['login', 'register', 'help'].includes($route.name)" />
    
        <main>
            <router-view />
        </main>
    
        <appfooter v-if="!['login', 'register'].includes($route.name)"/>
    
    </div>
    </template>

Mon fichier App.vue

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import Login from '../views/Login.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'home',
    component: Home
  },
  {
    path: '/login',
    name: 'login',
    component: Login
  },
  {
    path: '/register',
    name: 'register',
    component: Register
  }  
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router


10 commentaires

Il reproduit ce que @TommyF a dit


pourquoi ne pas utiliser écrire le code dans une application et voir si vous n'obtenez aucune erreur. Son approche ne fonctionne que pour l'écran de connexion si vous voulez qu'il l'implémente pour toute autre route, vous devez écrire des logiques différentes. Le mien fonctionne pour n'importe quelle route que vous voulez en passant simplement son nom dans le tableau. Je suis également très sûr que vous pouvez voir que son approche ne vérifie pas le nom de l'itinéraire, mais si un utilisateur est connecté lorsque la question dit "dans certaines routes"


D'accord, cela a du sens, mais dans votre description, je vois que vous insistez sur la directive v-if , comme si c'était le point principal. Et la directive v-if été utilisée dans la réponse précédente. Alors oui, vous avez raison, votre approche est différente, mais veuillez modifier la description de la réponse pour la mettre en valeur.


Hmmm oui c'est vrai mais c'est un peu difficile de l'expliquer en utilisant "v-if".


Eh bien, techniquement, je ne peux pas reprendre mon vote tant que vous ne modifiez pas votre message


Et je voulais dire "sans pas avec". Vous pouvez le dire si vous aviez raison. Dans ce cas, vous n'êtes pas. Vous venez de réagir sans comprendre le code. Et quel mal à mettre l'accent sur la directive v-if n'est-ce pas ce que j'ai utilisé ?. Si vous avez une meilleure façon de le présenter, vous êtes libre de le partager, ouvert à toutes les opinions que vous pourriez avoir. Merci.


J'ai modifié votre réponse pour que vous puissiez voir ce que je veux dire


J'ai également dû utiliser le non "!" opérateur pour comprend de travailler.


ah, ouais j'ai oublié ça. Pour une meilleure lisibilité, je mettrais cette condition à calculer comme ceci: isNavbar () {return! ['Login', 'register', 'help']. Includes (this. $ Route.name)} et puis le vérifier dans le modèle comme ceci: v-if = "isNavbar"


C'est une autre façon de le dire ... je l'essayerais. Je travaille actuellement sur le projet.