VUEJS应用程序具有不同的布局(例如登录布局,页面布局,注册等)



i使用vue-cli生成了一个项目。我看到项目有一个app.vue,这是该应用程序的主要布局 - 如果我没记错的话。在这里,我放置了我的基本HTML布局和<router-view></router-view>。现在的问题是,我需要完全不同的布局才能登录(不同的包装器,身体有不同的类),但是由于App.Vue的模板有点"固定"作为布局,因此我无法更改它。如何解决这个问题?有建议的方法吗?

我应该创建代表布局的新组件,以便在这种情况下,我的app.vue模板只有 <router-view></router-view>,然后将loginlayout.vue包括在其中?

我想我找到了解决方案。该方法的App.vue仅包含<router-view></router-view>,然后包括代表布局的不同组件(如果需要的话,包含<router-view>和子流程)。我在这里以这种方式找到了一个项目。

我认为这可以使事情变得更加干净和井井有条。恕我直言,隐藏了定义布局结构(所有Divs)的所有元素都太混乱了 - 尤其是对于更大的应用程序。

一个很好的解决方案是使用插槽

首先创建"布局组件"

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/>标签的位置。

您也可以拥有带有名称的多个插槽,请参阅完整的文档。

使用路线,尤其是儿童路线是一种很好的方式在Vue中具有共同布局的方法。

所有这些代码都使用VUE 2.x

首先拥有一个非常简单的vue组件,称为没有布局的应用程序。

app.vue

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

然后有一个路由文件,您将带入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/catalog文件加载catalog/layout

还要注意,如果您不喜欢拥有"子文件夹"(即帐户/登录而不是仅/登录)的想法,那么您可以像我在登录中显示的别名。

通过添加, alias: '/login',即使实际路线为/account/login

,用户也可以浏览到/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)
});

我为我的应用程序的每个主要部分(帐户,目录等)创建了一个布局。

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>

和目录的布局...

目录/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>

两个布局都使用标头和页脚等常见组件,但它们不需要。目录布局在Side NAV中具有类别,而帐户布局则没有。我将共同的组件放在组件/常见下。

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               

路线,普通应用程序和特定布局文件以及通用组件的组合应将您带到您想要的位置。

我使用路由器元来找到另一个解决方案。我只有一些组件需要另一个布局。

我添加了 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>

请参阅此处的演示项目。

i通过布局路由我的应用程序。例如,登录不需要结构,只需登录组件,但是其他页面需要,标头页夹等,因此这是我在路线中如何执行此操作的示例:

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

这两个布局模板都有一个路由器视图标签,因此您可以按照应用程序的不同部分构建布局。

i在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>

这样,我也能够通过道具控制顶部和底部NAV中显示的内容。

希望这会有所帮助!

我对任何"推荐方式"不了解,但是我的应用程序是这样的:

App.vue-只有顶部菜单栏(未经身份验证用户时未呈现)和每个组件(page)

<router-view></router-view>

因此,每个页面都可以完全不同。

有点不同意。也有同样的问题,这个答案使我感到困惑。基本上,当您有一个要在应用程序中到处重复使用的组件(例如页脚,标头)时,您可以将其保存在App.vue中。这是我的情况,我想在每个页面中都有页脚和标头,找到这个答案使我朝着错误的方向驶向,但是您 can 做到了,它 do 有效,例如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>&copy; {{ 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>

最新更新