64 votes

application vuejs 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 en quelque sorte le layout principal de l'application - si je ne me trompe pas. Ici, j'ai mis mon layout HTML de base et <router-view></router-view> . Maintenant le problème est que j'ai besoin d'une présentation complètement différente pour le login (différentes enveloppes, le corps a des classes différentes) mais je ne peux pas le changer car App.vue a un template qui est en quelque sorte "fixé" en tant que présentation. Comment aborder ce problème ? Est-ce qu'il y a une méthode recommandée ?

Devrais-je créer un nouveau composant qui représente la mise en page ? Dans ce cas, mon modèle App.vue ne contiendrait que <router-view></router-view> et que LoginLayout.vue y soit inclus ?

0 votes

Pour les curieux, voici un lien avec des options intéressantes pour gérer les mises en page avec vue : markus.oberlehner.net/blog/dynamic-vue-layout-components

0 votes

Une bonne solution est : levelup.gitconnected.com/

50voto

user2343398 Points 579

Je pense avoir trouvé une solution. L'approche a App.vue contenant uniquement <router-view></router-view> puis en incluant différents composants qui représentent la mise en page (si nécessaire, en contenant des <router-view> et les itinéraires secondaires). J'ai trouvé un projet qui l'utilise de cette manière aquí .

Je pense que cela permet de garder les choses plus propres et organisées. Pour moi, cacher tous les éléments qui définissent la structure de la présentation (toutes les divs) serait trop compliqué, en particulier pour les applications de grande taille.

0 votes

Les itinéraires pour les enfants, tels qu'ils sont présentés dans le projet en question, sont très bien conçus !

1 votes

Je préfère cette approche, car le routage de tous les composants se fait dans le routeur à partir de CoPilote .

1 votes

Cette approche est également décrite dans le guide Vue Router : Essentiels - Routes imbriquées .

42voto

lipsumar Points 71

Une solution intéressante consiste à utiliser créneaux

Créez d'abord 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>

Il est ensuite utilisé 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>

"Hello world" apparaîtra à l'endroit où le <slot/> est.

Vous pouvez également avoir plusieurs emplacements avec des noms, voir la rubrique documents complets .

4 votes

Je pense que c'est la meilleure approche, car c'est exactement ce pour quoi les créneaux sont prévus.

0 votes

Parfait. Pas besoin d'utiliser une bibliothèque/composant tiers.

8 votes

Cette situation est facile à gérer, mais peut poser quelques problèmes : Although, in terms of flexibility, this approach has everything we need, there is one huge downside of wrapping our views in a static layout component: the component is destroyed and re-created every time the route changes. de aquí

11voto

lingceng Points 1720

Je trouve une autre solution en utilisant routeur meta . J'ai juste quelques composants qui ont besoin d'une autre mise en page.

J'ai ajouté un 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,
      },
    },
  ],
});

Ensuite, le rendu de la mise en page se fait de manière conditionnelle avec playLayout en 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 aquí .

0 votes

Votre approche, combinée à celle de @user2343398, est parfaite.

9voto

Chad Carter Points 361

L'utilisation des routes, et en particulier des routes enfants, est une excellente façon d'aborder les mises en page communes dans Vue.

Tout ce code utilise Vue 2.x

Commencez par avoir un composant vue très simple appelé App qui n'a pas de mise en page.

app.vue

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

Créez ensuite un fichier Routes que vous introduirez 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 le lazy loading (avec webpack), donc ne laissez pas l'option () => import(...) vous lancer. Il aurait pu s'agir d'un simple import(...) si vous souhaitez un chargement rapide.

L'important, ce sont les itinéraires des enfants. Nous définissons donc le chemin principal de /account d'utiliser le /components/account/layout.vue mais les deux premiers enfants spécifient la vue du contenu principal (Login). J'ai choisi de procéder de cette manière parce que si quelqu'un navigue simplement vers /account, je veux l'accueillir avec l'écran de connexion. Il peut être approprié pour votre application que /account soit une page d'atterrissage où ils peuvent vérifier l'historique des commandes, changer les mots de passe, etc...

J'ai fait la même chose pour le catalogue... / y /catalog tous deux chargent le catalog/layout avec le /catalog/catalog fichier.

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

En ajoutant , alias: '/login' cela signifie que les utilisateurs peuvent naviguer vers /login même si l'itinéraire réel est /account/login .

C'est la clé du problème, mais pour essayer de compléter l'exemple...

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

boot.(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 sections principales 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 du catalogue...

catalog/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 présentations utilisent des composants communs tels que l'en-tête et le pied de page, mais ce n'est pas nécessaire. La présentation du catalogue comporte des catégories dans la barre de navigation latérale, alors que la présentation du compte n'en comporte pas. Je place mes composants communs sous components/common.

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 générale 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 des routes, d'un app.vue simple, de fichiers de mise en page spécifiques et de composants communs devrait vous permettre d'atteindre vos objectifs.

7voto

Tremendus Apps Points 747

J'achemine mes applications par l'intermédiaire d'un modèle. Par exemple, la connexion ne nécessite pas de structure, juste le composant de connexion, mais d'autres pages nécessitent un en-tête, un pied de page, etc :

// 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 router-view, ce qui vous permet de construire vos présentations comme vous le souhaitez pour les différentes parties de l'application.

2 votes

Pouvez-vous nous donner un exemple ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X