web-dev-qa-db-ja.com

異なるレイアウト(ログインレイアウト、ページレイアウト、サインアップなど)のvuejsアプリケーション

Vue-cliを使用してプロジェクトを生成しました。プロジェクトには、アプリのメインレイアウトであるApp.vueが1つあります-間違っていなければ。ここに、基本的なHTMLレイアウトと<router-view></router-view>を配置します。問題は、ログイン用に完全に異なるレイアウトが必要なことです(異なるラッパー、ボディには異なるクラスがあります)が、App.vueにはレイアウトとして「固定」されたテンプレートがあるため、変更できません。この問題へのアプローチ方法推奨される方法はありますか?

レイアウトを表す新しいコンポーネントを作成する必要があります。その場合、App.vueテンプレートには<router-view></router-view>のみが含まれ、LoginLayout.vueが含まれますか?

42
user2343398

私は解決策を見つけたと思います。このアプローチには、App.vueのみを含む<router-view></router-view>があり、レイアウトを表すさまざまなコンポーネントが含まれます(必要に応じて、<router-view>およびサブルートが含まれます)。そのように使用しているプロジェクトを見つけました here

私はそれが物事をよりきれいで整理された状態に保つと思います。私見、レイアウト構造を定義するすべての要素(すべてのdiv)を非表示にするのは、特に大きなアプリの場合は面倒です。

39
user2343398

このための良い解決策は slots を使用することです

最初に「レイアウトコンポーネント」を作成します

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>

次に、別のコンポーネントで使用します。

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

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

<slot/>タグがある場所に「Hello world」が表示されます。

名前付きの複数のスロットを持つこともできます。 完全なドキュメント を参照してください。

32
lipsumar

router meta を使用して別の解決策を見つけます。別のレイアウトが必要なコンポーネントがいくつかあります。

plainLayoutメタキーを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,
      },
    },
  ],
});

次にplayLayoutを使用して、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>

デモプロジェクトを参照してください こちら

7
lingceng

レイアウトを介してアプリをルーティングします。たとえば、ログインにはログインコンポーネントだけの構造は必要ありませんが、他のページにはヘッダーフッターなどが必要です。したがって、ルートでこれを行う方法の例を次に示します。

// 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')
    }
  }
}

これらのレイアウトテンプレートにはどちらもルータービュータグがあるため、アプリのさまざまな部分に必要なレイアウトを作成できます。

7
Tremendus Apps

ルート、特に子供のルートを利用することは、Vueで共通のレイアウトを持つための素晴らしい方法です。

このコードはすべてVue 2.xを利用しています

レイアウトのないAppという非常にシンプルなvueコンポーネントを用意することから始めます。

app.vue

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

次に、Vueインスタンスに取り込むRoutesファイルを用意します。

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 }    
        ]    
    }        
    ]
})

コードは(webpackを使用した)遅延読み込みを使用しているため、() => import(...)がユーザーをスローしないようにしてください。積極的な読み込みが必要な場合は、import(...)でした。

重要なのは、子ルートです。したがって、/accountのメインパスを設定して/components/account/layout.vueを利用しますが、最初の2つの子はメインコンテンツvue(ログイン)を指定します。誰かが/ accountを閲覧しただけならログイン画面で挨拶したいので、私はこの方法を選択しました。/accountは、注文履歴を確認したり、パスワードを変更したりできるランディングページであることがアプリに適している場合があります。

カタログについても同じことをしました... //catalogは両方ともcatalog/layoutファイルに/catalog/catalogをロードします。

また、「サブフォルダ」(つまり、/ loginの代わりにaccount/login)を使用するという考えが気に入らない場合は、ログインに表示されるエイリアスを使用できることに注意してください。

, alias: '/login'を追加することは、実際のルートが/loginであっても、ユーザーが/account/loginを参照できることを意味します。

それが全体の鍵ですが、例を完成させようとするだけです...

App.vueとルートを接続するブートファイルを次に示します。

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)
});

アプリのメインセクション(アカウント、カタログなど)ごとにlayout.vueファイルを作成しました。

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>

カタログのレイアウト...

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>

どちらのレイアウトもヘッダーやフッターなどの一般的なコンポーネントを使用しますが、必要はありません。カタログレイアウトにはサイドナビゲーションにカテゴリがありますが、アカウントレイアウトにはありません。 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>

全体的なファイル構造

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               

ルート、プレーンなapp.vue、および特定のレイアウトファイルの組み合わせは、一般的なコンポーネントとともに、目的の場所に到達するはずです。

6
Chad Carter

App.vueでルートをグローバルに動的にチェックし、それを使用して表示する必要があるものを決定します。

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>

そうすれば、小道具を使って上下のナビゲーションに表示されるものを制御することもできます。

お役に立てれば!

1
ericgm

私はそれが古いことを知っていますが、 nuxt.js 最近レイアウトをサポートしています。ご覧ください。

0
Tiago Matos

「推奨される方法」については知りませんが、私のアプリは次のように構成されています。

App.vue-トップメニューバー(ユーザーが認証されていない場合はレンダリングされません)および各コンポーネント(ページ)の<router-view></router-view>

そのため、すべてのページでまったく異なるレイアウトを使用できます。

0
lukpep