我使用vue-cli生成了一个项目。我看到项目有一个App.vue,这是应用程序的主要布局 - 如果我没有弄错的话。在这里,我将基本的HTML布局和<router-view></router-view>
放在一起。现在的问题是我需要完全不同的登录布局(不同的包装器,主体有不同的类)但我不能改变它,因为App.vue有模板有点&#34;固定&#34;作为布局。如何处理这个问题?有推荐的方法吗?
我是否应该创建代表布局的新组件,因此在这种情况下,我的App.vue模板只会包含<router-view></router-view>
,然后会包含LoginLayout.vue?
答案 0 :(得分:37)
我想我找到了解决方案。该方法的App.vue
仅包含<router-view></router-view>
,然后包含表示布局的不同组件(如果需要,包含<router-view>
和子路由)。我找到了一个以这种方式使用它的项目here。
我认为它可以使事情变得更加整洁有序。恕我直言,隐藏所有定义布局结构的元素(所有div)都会太乱 - 特别是对于更大的应用程序。
答案 1 :(得分:30)
一个很好的解决方案是使用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>
“Hello world”将出现在<slot/>
标记所在的位置。
您还可以拥有多个名称的插槽,请参阅complete docs。
答案 2 :(得分:7)
我通过布局路由我的应用程序。例如登录不需要结构,只需登录组件,但其他页面需要,页眉页脚等,所以这里是我在我的路线中如何做到这一点的一个例子:
// 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')
}
}
}
这两个布局模板都有一个路由器视图标记,因此您可以根据需要为应用的不同部分构建布局。
答案 3 :(得分:6)
使用路由,特别是子路由是在Vue中使用公共布局的好方法。
所有这些代码都使用了Vue 2.x
首先要有一个名为App的非常简单的vue组件,它没有布局。
<强> app.vue 强>
<template>
<router-view></router-view>
</template>
然后有一个Routes文件,你将它带入你的Vue实例。
<强>路线(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
,但是前两个孩子指定主要内容vue(登录)。我选择这样做是因为如果有人只是浏览/帐户我想用登录屏幕问候他们。您的应用可能适合/帐户是一个登录页面,他们可以检查订单历史记录,更改密码等...
我为目录做了同样的事情...... /
和/catalog
都将catalog/layout
加载到/catalog/catalog
文件。
另请注意,如果您不喜欢拥有&#34;子文件夹&#34; (即帐户/登录而不仅仅是/ login)然后你可以在我登录时显示别名。
通过添加, alias: '/login'
,即使实际路线为/login
,用户也可以浏览/account/login
。
这是整个事情的关键,但只是试图让这个例子完整......
这是我的启动文件,它连接了我的app.vue和路由:
<强>引导(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文件。
帐户/ 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>
目录的布局......
<强>目录/ 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下。
<强>公共/ 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和特定的布局文件以及常用组件的组合应该可以让您到达目的地。
答案 4 :(得分:5)
我使用router meta找到了另一种解决方案。我只需要一些组件需要另一种布局。
我在 src / router / index.js 中添加了 plainLayout 元键。
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,
},
},
],
});
然后使用 src / App.vue 中的 playLayout 有条件地渲染布局。
<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>
查看演示项目here。
答案 5 :(得分:1)
我在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>
这样我也可以通过道具控制顶部和底部导航中显示的内容。
希望这有帮助!
答案 6 :(得分:0)
我不知道任何&#34;推荐方式&#34;但我的应用程序结构如下:
App.vue
- 只是顶部菜单栏(未经过身份验证时未呈现)和每个组件的<router-view></router-view>
(页面)
所以每个页面都可以有完全不同的布局。
答案 7 :(得分:0)
我知道它现在已经过时了但nuxt.js支持布局。看看。
答案 8 :(得分:0)
评论已接受的答案
不同意这一点。有同样的问题,这个答案使我感到困惑。基本上,当您拥有要在应用程序中的任何地方(例如页脚,页眉)重用的组件时,可以将其保留在App.vue
中。在我的情况下,我想在每页中都添加页脚和页眉,找到这个答案会使我误入歧途,但是您可以做到这一点并且确实有效,例如App.vue
:
<template>
<div id="app">
<app-header />
<router-view />
<app-footer />
</div>
</template>
<script lang="ts">
// Imports related to Vue.js core.
import { Component, Vue } from "vue-property-decorator";
// Imports related with custom logic.
import FooterComponent from "@/components/Footer.vue";
import HeaderComponent from "@/components/Header.vue";
@Component({
components: {
"app-footer": FooterComponent,
"app-header": HeaderComponent
}
})
export default class App extends Vue {}
</script>
<style lang="scss" scoped>
</style>
Footer.vue
(位于components/Footer.vue
中):
<template>
<div>
<footer>
<div>© {{ year }} MyCompany</div>
</footer>
</div>
</template>
<script lang="ts">
// Imports related to Vue.js core.
import { Component, Vue } from "vue-property-decorator";
@Component({})
export default class FooterComponent extends Vue {
public year = new Date().getFullYear();
}
</script>
<style lang="scss" scoped>
</style>
Header.vue
(位于components/Header.vue
中):
<template>
<div>
<header>
<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>
<router-link to="/contact">Contact</router-link>
</header>
</div>
</template>
<script lang="ts">
// Imports related to Vue.js core.
import { Component, Vue } from "vue-property-decorator";
@Component({})
export default class HeaderComponent extends Vue {}
</script>
<style lang="scss" scoped>
</style>