Vue-cliを使用してプロジェクトを生成しました。プロジェクトには、アプリのメインレイアウトであるApp.vueが1つあります-間違っていなければ。ここに、基本的なHTMLレイアウトと<router-view></router-view>
を配置します。問題は、ログイン用に完全に異なるレイアウトが必要なことです(異なるラッパー、ボディには異なるクラスがあります)が、App.vueにはレイアウトとして「固定」されたテンプレートがあるため、変更できません。この問題へのアプローチ方法推奨される方法はありますか?
レイアウトを表す新しいコンポーネントを作成する必要があります。その場合、App.vueテンプレートには<router-view></router-view>
のみが含まれ、LoginLayout.vueが含まれますか?
私は解決策を見つけたと思います。このアプローチには、App.vue
のみを含む<router-view></router-view>
があり、レイアウトを表すさまざまなコンポーネントが含まれます(必要に応じて、<router-view>
およびサブルートが含まれます)。そのように使用しているプロジェクトを見つけました here 。
私はそれが物事をよりきれいで整理された状態に保つと思います。私見、レイアウト構造を定義するすべての要素(すべてのdiv)を非表示にするのは、特に大きなアプリの場合は面倒です。
このための良い解決策は 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」が表示されます。
名前付きの複数のスロットを持つこともできます。 完全なドキュメント を参照してください。
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>
デモプロジェクトを参照してください こちら 。
レイアウトを介してアプリをルーティングします。たとえば、ログインにはログインコンポーネントだけの構造は必要ありませんが、他のページにはヘッダーフッターなどが必要です。したがって、ルートでこれを行う方法の例を次に示します。
// 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')
}
}
}
これらのレイアウトテンプレートにはどちらもルータービュータグがあるため、アプリのさまざまな部分に必要なレイアウトを作成できます。
ルート、特に子供のルートを利用することは、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、および特定のレイアウトファイルの組み合わせは、一般的なコンポーネントとともに、目的の場所に到達するはずです。
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>
そうすれば、小道具を使って上下のナビゲーションに表示されるものを制御することもできます。
お役に立てれば!
私はそれが古いことを知っていますが、 nuxt.js 最近レイアウトをサポートしています。ご覧ください。
「推奨される方法」については知りませんが、私のアプリは次のように構成されています。
App.vue
-トップメニューバー(ユーザーが認証されていない場合はレンダリングされません)および各コンポーネント(ページ)の<router-view></router-view>
そのため、すべてのページでまったく異なるレイアウトを使用できます。