動態Vue.js佈局組件

動態Vue.js佈局組件

前言

  • vue.js是漸進加強的視圖庫,能夠做爲.html頁面部分使用,也能夠結合vue-router、vuex、axios用來構建單頁面或多頁面應用。以開發單頁面爲例,開發過程當中爲遇到,不一樣的頁面須要使用不一樣的頁面佈局狀況,下面咱們將探索Vue.js中處理佈局的多種方式。
  • 構建Vue Router驅動的Vue應用程序.(基本結構以下),它能很好的工做。(但假設有一個結賬流程,您不想顯示導航。或者您可能有帶側邊欄的產品頁面和沒有側邊欄的其餘頁面等等)面對這種多樣性要求,咱們要怎麼作來知足業務需求的同時,保持代碼的可維護、易擴展呢?下面一塊兒來探討。
<template>
  <div class="App">
    <nav class="App__nav">
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link>
    </nav>
    <router-view/>
    <footer>
      &copy; Awesome Company
    </footer>
  </div>
</template>
複製代碼

實現方式

  1. 條件渲染:最基本和最直接的方法是有條件地渲染布局的某些部分。所以,您能夠將v-if指令添加到佈局的某些部分,並根據須要切換可見性。
<template>
   <div class="App">
    <nav v-if="showNav" class="App__nav">
       <router-link to="/">Home</router-link> |
       <router-link to="/about">About</router-link>
     </nav>
     <router-view/>
     <footer v-if="showFooter">
       &copy; Awesome Company
     </footer>
   </div>
 </template>
複製代碼

-說明:這種方法的一個問題是,您必須控制應用程序中某些元素的可見性,經過在Vue.js中處理全局狀態。雖然若是您不須要很是複雜的佈局而且只是想在某些上下文中隱藏某些元素,這多是正確的方法,但隨着應用程序的增加,這種方法可能會成爲維護的噩夢。html

  1. 靜態佈局包裝器組件:使用普通組件(包含佈局不一樣部分的一個或多個插槽)做爲視圖的包裝器,它提供了很大的靈活性,而且感受不像條件渲染方法那麼髒。
// app.vue
<template>
  <div class="App">
    <router-view/>
  </div>
</template>

// LayoutDefault.vue
<template>
  <div class="LayoutDefault">
    <nav class="LayoutDefault__nav">
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link>
    </nav>
    <main class="LayoutDefault__main">
      <slot/>
    </main>
    <footer class="LayoutDefault__footer">
      &copy; Awesome Company
    </footer>
  </div>
</template

// home.vue
<template>
  <layout-default>
    <div class="Home">
      <h1>Home</h1>
      <p>
        Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
        eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
        voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
        clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
        amet.
      </p>

      <h2>Amet sit</h2>
      <p>
        Eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
        voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
        clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
        amet.
      </p>
    </div>
  </layout-default>
</template>

<script>
import LayoutDefault from '../layouts/LayoutDefault.vue';

export default {
  name: 'Home',
  components: {
    LayoutDefault,
  },
};
</script>
複製代碼
  • 說明:
  • Home.vue組件實現LayoutDefault包裝器組件以包裝其內容。
  • 雖然在靈活性方面,這種方法具備咱們所需的一切,可是在靜態佈局組件中包裝咱們的視圖有一個巨大的缺點:每次路由更改時,組件都會被銷燬並從新建立。
  • 這不只會對性能產生負面影響,由於客戶端必須在每次路由更改時一次又一次地從新建立佈局組件(以及嵌套在其中的全部其餘組件),但這也意味着您必須獲取某些數據,您在佈局的某個組件中使用的每一個路徑更改。
  • 靜態佈局包裝器組件很是強大且靈活,但它們也帶來了成本。讓咱們一塊兒探討一下,若是咱們可以提出一種方法,它具備靜態包裝器組件的全部積極特性,但沒有一個是負面的,那麼它就是最佳解決方案
  1. 動態佈局包裝器組件
  • 在咱們開始以前,先介紹一下Vue.js中的組件系統的一個很是強大的功能動態組件
<component :is="SomeComponent"/>
複製代碼
  • 在上面的示例中,SomeComponent是一個變量,能夠動態分配給任何組件,每次分配不一樣的組件時,模板都會在您定義標記的位置呈現新組件。
  • 咱們可使用動態組件來構建一個很是靈活且高性能的動態佈局系統。代碼以下:
// app.vue
<template>
  <component :is="layout">
    <router-view :layout.sync="layout"/>
  </component>
</template>

<script>
export default {
  name: 'App',
  data() {
    return {
      layout: 'div',
    };
  },
};
</script>

// home.vue
<template>
  <div class="Home">
    <h1>Home</h1>
    <!-- ... -->
  </div>
</template>

<script>
import LayoutDefault from '../layouts/LayoutDefault.vue';

export default {
  name: 'Home',
  created() {
    this.$emit('update:layout', LayoutDefault);
  },
};
</script>
複製代碼
  • 上面你能夠看到咱們再也不將Layout視圖的模板包裝在LayoutDefault組件中,但咱們加載組件並將其做爲咱們在App基礎組件中定義的layout屬性的新值發出。這意味着,一旦建立Home組件,包裝呈現Home組件的的動態組件將被從新呈現,以呈現咱們在created()鉤子中發出的組件。
  • 爲何說這比靜態包裝器組件更好? 主要區別在於,佈局組件不是路由器視圖組件的一部分,而是包裹它。這意味着,若是視圖組件使用與先前視圖組件不一樣的佈局,則僅==從新呈現佈局組件==。
  1. 繼續重構代碼使得使用動態佈局更加直觀
// 修改home.vue
<template>
   <layout name="LayoutDefault">
     <div class="Home">
       <h1>Home</h1>
       <!-- ... -->
     </div>
   </layout>
</template>
 
<script>
  import Layout from '../layouts/Layout';
 
  export default {
    name: 'Home',
    components: {
      Layout,
    },
  };
</script>


// src/layouts/Layout.js
import Vue from 'vue';

export default {
  name: 'Layout',
  props: {
    name: {
      type: String,
      required: true,
    },
  },
  created() {
    // Check if the layout component
    // has already been registered.
    if (!Vue.options.components[this.name]) {
      Vue.component(
        this.name,
        () => import(`../layouts/${this.name}.vue`),
      );
    }

    this.$parent.$emit('update:layout', this.name);
  },
  render() {
    return this.$slots.default[0];
  },
};
<templat
複製代碼

參考連接