動態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>
© Awesome Company
</footer>
</div>
</template>
複製程式碼
實現方式
- 條件渲染:最基本和最直接的方法是有條件地渲染布局的某些部分。因此,您可以將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">
© Awesome Company
</footer>
</div>
</template>
複製程式碼
-說明:這種方法的一個問題是,您必須控制應用程式中某些元素的可見性,通過在Vue.js中處理全域性狀態。雖然如果您不需要非常複雜的佈局並且只是想在某些上下文中隱藏某些元素,這可能是正確的方法,但隨著應用程式的增長,這種方法可能會成為維護的噩夢。
- 靜態佈局包裝器元件:使用普通元件(包含佈局不同部分的一個或多個插槽)作為檢視的包裝器,它提供了很大的靈活性,並且感覺不像條件渲染方法那麼髒。
// 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">
© 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包裝器元件以包裝其內容。
- 雖然在靈活性方面,這種方法具有我們所需的一切,但是在靜態佈局元件中包裝我們的檢視有一個巨大的缺點:每次路由更改時,元件都會被銷燬並重新建立。
- 這不僅會對效能產生負面影響,因為客戶端必須在每次路由更改時一次又一次地重新建立佈局元件(以及巢狀在其中的所有其他元件),但這也意味著您必須獲取某些資料,您在佈局的某個元件中使用的每個路徑更改。
- 靜態佈局包裝器元件非常強大且靈活,但它們也帶來了成本。讓我們一起探討一下,如果我們能夠提出一種方法,它具有靜態包裝器元件的所有積極特性,但沒有一個是負面的,那麼它就是最佳解決方案
- 動態佈局包裝器元件
- 在我們開始之前,先介紹一下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()鉤子中發出的元件。
- 為什麼說這比靜態包裝器元件更好? 主要區別在於,佈局元件不是路由器檢視元件的一部分,而是包裹它。這意味著,如果檢視元件使用與先前檢視元件不同的佈局,則僅==重新呈現佈局元件==。
- 繼續重構程式碼使得使用動態佈局更加直觀
// 修改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
複製程式碼