web-dev-qa-db-fra.com

Vuejs application avec différentes mises en page (par exemple, mise en page de connexion, mise en page, inscription, etc.)

J'ai généré un projet en utilisant vue-cli. Je vois que le projet a un App.vue qui est un peu la disposition principale de l'application - si je ne me trompe pas. Ici, je mets ma mise en page HTML de base et <router-view></router-view>. Maintenant, le problème est que j'ai besoin d'une mise en page complètement différente pour la connexion (différents wrappers, body a différentes classes) mais je ne peux pas la changer car App.vue a un modèle qui est un peu "corrigé" en tant que mise en page. Comment aborder ce problème? Y a-t-il moyen recommandé?

Devrais-je créer un nouveau composant qui représente la mise en page afin que dans ce cas, mon modèle App.vue ne contienne que <router-view></router-view> puis LoginLayout.vue serait-il inclus?

42
user2343398

Je pense avoir trouvé une solution. L'approche a App.vue contenant seulement <router-view></router-view> puis en incluant différents composants qui représentent la mise en page (si nécessaire, contenant <router-view> et subroutes). J'ai trouvé un projet en l'utilisant de cette façon ici .

Je pense que ça garde les choses plus propres et organisées. IMHO, masquer tous les éléments qui définissent la structure de présentation (tous les divs) serait trop compliqué, surtout pour les plus grandes applications.

39
user2343398

Une bonne solution pour cela consiste à utiliser slots

Commencez par créer votre "composant de mise en page"

src/components/layouts/basic.vue

<template>
  <div class="basic-layout">
    <header>[Company logo]</header>
    <hr>

    <slot/>

    <hr>
    <footer>
      Made with ❤ at Acme
    </footer>
  </div>
</template>

Puis utilisez-le dans un autre composant:

<template>
  <layout-basic>
    <p>Hello world!</p>
  </layout-basic>
</template>

<script>
  import LayoutBasic from '@/components/layouts/basic'
  export default {
    components: {
      LayoutBasic
    }
  }
</script>

"Bonjour tout le monde" apparaîtra où le <slot/> balise est.

Vous pouvez également avoir plusieurs emplacements avec des noms, voir le documentation complète .

32
lipsumar

Je trouve une autre solution en utilisant routeur méta . J'ai juste quelques composants besoin d'une autre mise en page.

J'ai ajouté une plainLayout clé méta dans src/router/index.js.

export default new Router({
  mode: 'history',
  linkExactActiveClass: 'app-head-menu--active',
  routes: [
    {
      path: '/',
      component: Features,
    },
    {
      path: '/comics/:id',
      component: Comic,
      props: true,
    },
    {
      path: '/comics/:comic_id/:chapter_index',
      component: Chapter,
      props: true,
      meta: {
        plainLayout: true,
      },
    },
  ],
});

Rendez ensuite la mise en page de manière conditionnelle avec playLayout dans src/App.vue.

<template>
  <div>
    <div v-if="!$route.meta.plainLayout">
      <div class="app-head">
      </div>
      <div class="app-content">
        <router-view/>
      </div>
    </div>

    <div v-if="$route.meta.plainLayout">
      <router-view/>
    </div>
  </div>
</template>

<script>
export default {
  name: 'app',
};
</script>

Voir un projet de démonstration ici .

7
lingceng

Je route mes applications à travers une mise en page. Par exemple, la connexion ne nécessite aucune structure, mais uniquement le composant de connexion, mais d’autres pages nécessitent un en-tête de pied de page, etc. Voici donc un exemple de la façon dont je procède de la sorte:

// application routes
'/secure': {
  name: 'secure',
  component: require('../components/layouts/default'),
  subRoutes: {
    '/home': {
      name: 'home',
      component: require('../components/home/index')
    }
  }
}

//- public routes
'/insecure': {
  name: 'insecure',
  component: require('../components/layouts/full-bleed'),
  subRoutes: {
    '/login': {
      name: 'login',
      component: require('../components/session/login')
    }
  }
}

Ces deux modèles de présentation ont une balise de vue du routeur, vous pouvez donc construire vos présentations selon vos besoins pour différentes parties de l'application.

7
Tremendus Apps

Utiliser Routes, et en particulier les itinéraires pour enfants, est un excellent moyen d’avoir des dispositions communes dans Vue.

Tout ce code utilise Vue 2.x

Commencez par avoir un composant très simple vue appelé App qui n’a pas de présentation.

app.vue

<template>
    <router-view></router-view>
</template>

Ensuite, ayez un fichier Routes que vous allez importer dans votre instance Vue.

Routes. (Ts | js)

import Vue from 'vue'
import VueRouter from 'vue-router'

const NotFoundComponent = () => import('./components/global/notfound.vue')
const Login = () => import('./components/account/login.vue')
const Catalog = () => import('./components/catalog/catalog.vue')

export default new VueRouter({
    mode: 'history',
    linkActiveClass: 'is-active',
    routes: [
    //Account
    { path: '/account', component: () => import('./components/account/layout.vue'),
        children: [
            { path: '', component: Login },
            { path: 'login', component: Login, alias: '/login' },
            { path: 'logout', 
                beforeEnter (to: any, from: any, next: any) {
                    //do logout logic
                    next('/');
                } 
            },
            { path: 'register', component: () => import('./components/account/register.vue') }
        ]
    },

    //Catalog (last because want NotFound to use catalog's layout)
    { path: '/', component: () => import('./components/catalog/layout.vue'),
        children: [
            { path: '', component: Catalog },
            { path: 'catalog', component: Catalog },
            { path: 'category/:id', component: () => import('./components/catalog/category.vue') },
            { path: 'product', component: () => import('./components/catalog/product.vue') },
            { path: 'search', component: () => import(`./components/catalog/search.vue`)} ,
            { path: 'basket', component: () => import(`./components/catalog/basket.vue`)} ,
            { path: '*', component: NotFoundComponent }    
        ]    
    }        
    ]
})

Le code utilise un chargement différé (avec webpack), alors ne laissez pas le () => import(...) Vous jeter. Cela aurait pu être import(...) si vous vouliez un chargement rapide.

Le bit important est les itinéraires des enfants. Nous avons donc défini le chemin principal de /account Pour utiliser le /components/account/layout.vue, Mais les deux premiers enfants ont spécifié le contenu principal vue (Connexion). J'ai choisi de faites-le de cette façon parce que si quelqu'un accède à/compte, je souhaite les saluer avec l'écran de connexion.Il peut être approprié pour votre application que/compte soit une page de destination sur laquelle ils pourraient consulter l'historique de la commande, modifier les mots de passe, etc. ..

J'ai fait la même chose pour le catalogue ... / Et /catalog Ont tous deux chargé le catalog/layout Avec le fichier /catalog/catalog.

Notez également que si vous n’aimez pas l’idée d’avoir des "sous-dossiers" (c’est-à-dire compte/connexion au lieu de/login), vous pouvez avoir des alias comme je le montre dans la connexion.

En ajoutant , alias: '/login', Cela signifie que les utilisateurs peuvent accéder à /login Même si l'itinéraire réel est /account/login.

C'est la clé de tout, mais juste pour essayer de compléter l'exemple ...

Voici mon fichier de démarrage qui relie mon app.vue et mes routes:

démarrage. (ts | js)

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

import App from './components/app.vue';

import router from './routes';

new Vue({
    el: '#app',
    router,
    render: h => h(App)
});

J'ai créé un fichier layout.vue pour chacune des principales sections de mon application (compte, catalogue, etc.).

account/layout.vue

<template>
<div>
    <cc-header></cc-header>

    <div class="container">
        <main>
            <router-view></router-view>
        </main>
        <aside>
        </aside>
    </div>

    <cc-footer></cc-footer>    
</div>
</template>

<script lang="ts">

import ccHeader from "../common/cc-header.vue"
import ccFooter from "../common/cc-footer.vue"

export default {
    components: {
        ccHeader,
        ccFooter
    }
}

</script>

<style lang="scss" scoped>

.container {
    display: flex;
}

main {
    flex: 3;
    order: 2;
}

aside {
    flex: 1;
    order: 1;
}
</style>

Et la mise en page pour le catalogue ...

catalogue/layout.vue

<template>
<div>
<cc-header></cc-header>

<div class="catalog-container">
    <main class="catalog">
        <router-view></router-view>
    </main>
    <cc-categories></cc-categories>
</div>

<cc-footer></cc-footer>    
</div>

</template>

<script lang="ts">
import ccHeader from "../common/cc-header.vue"
import ccFooter from "../common/cc-footer.vue"

import ccCategories from "./cc-categories.vue"

export default {
    components: {
        ccCategories,
        ccHeader,
        ccFooter
    },
    data : function() : any {
    return {
        search: ''
    }        
},
}
</script>

<style lang="scss" scoped>
.catalog-container {
        display: flex;
    }

    .category-nav {
        flex: 1;
        order: 1;
    }

    .catalog {
        flex: 3;
        order: 2;
    }
</style>

Les deux dispositions utilisent des composants communs tels que l'en-tête et le pied de page, mais ils n'en ont pas besoin. La présentation du catalogue comporte des catégories dans la barre de navigation latérale, contrairement à la présentation du compte. Je mets mes composants communs sous composants/commun.

common/footer.vue

<template>
<div>
    <hr />
    <footer>
        <div class="footer-copyright">
            <div>© Copyright {{year}} GlobalCove Technologies, LLC</div>
            <div>All rights reserved. Powered by CoveCommerce.</div>
        </div>
    </footer>
</div>
</template>

<script lang="ts">
    import Vue from "vue";
    export default Vue.component('cc-footer', {

        data : function() : any {
        return {
            year: new Date().getFullYear()
        }        
    },
    })

</script>

<style lang="scss">
</style>

Structure globale du fichier

src/
    boot.ts
    routes.ts

    components/
        app.vue

        catalog/
            layout.vue
            catalog.vue
            category.vue
            product.vue
            search.vue
            basket.vue

        account/
            layout.vue
            login.vue
            register.vue

        global/
            notfound.vue

        common/
            cc-header.vue
            cc-footer.vue               

La combinaison de routes, d’un fichier app.vue simple et de fichiers de présentation spécifiques, ainsi que de composants courants, devrait vous permettre d’atteindre votre objectif.

6
Chad Carter

Je vérifie dynamiquement la route de manière globale sur App.vue et l’utilise pour déterminer ce qui doit être affiché.

App.vue

    <template>
      <div id="app">
        <top :show="show" v-if="show.header"></top>
        <main>
          <router-view></router-view>
        </main>
        <bottom v-if="show.footer"></bottom>
      </div>
    </template>

    <script>
    export default {
       mounted: function() {
         if(window.location.hash == "#/" || window.location.hash.indexOf('route')) {
            vm.show.header = true
            vm.show.footer = true
            vm.show.slideNav = true
          }
       }


       watch: {
         $route: function() {
           // Control the Nav when the route changes
           if(window.location.hash == "#/" || window.location.hash.indexOf('route')) {
             vm.show.header = true
             vm.show.footer = true
             vm.show.slideNav = true
           }
         }
       }
    }
    </script>

De cette façon, je suis également capable de contrôler ce qui est montré dans les navettes du haut et du bas à l'aide d'accessoires.

J'espère que cela t'aides!

1
ericgm

Je sais que c'est vieux mais nuxt.js support layout aujourd'hui. Regarde.

0
Tiago Matos

Je ne connais aucune méthode recommandée, mais mon application est structurée comme suit:

App.vue - uniquement la barre de menus supérieure (qui n'est pas rendue lorsque l'utilisateur n'est pas authentifié) et <router-view></router-view> pour chaque composant (page)

Ainsi, chaque page pourrait avoir des mises en page totalement différentes.

0
lukpep