Dynamic vue.js layout components
preface
- Vue. js is a progressively enhanced visual library, which can be used as part of an. HTML page, or combined with Vue-Router, Vuex, axios to build single-page or multi-page applications. Take the development of a single page as an example. During the development process, different pages need to use different page layouts. Below, we will explore various ways to deal with layout in vue.js.
- Build Vue Router driven Vue application. (basic structure below), it works well. (But suppose you have an checkout process and you don’t want to show the navigation. Or you might have product pages with sidebars, other pages without sidebars, etc.) With this diversity, how do we keep our code maintainable and extensible while meeting our business needs? Let’s talk about it.
<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>
Copy the code
implementation
- Conditional rendering: The most basic and straightforward method is to conditionally render parts of a layout. Therefore, you can add V-if directives to certain parts of the layout and switch visibility as needed.
<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>
Copy the code
– Note: One problem with this approach is that you have to control the visibility of certain elements in your application by handling global state in vue.js. While this might be the right approach if you don’t need a very complex layout and just want to hide certain elements in certain contexts, it can become a maintenance nightmare as your application grows.
- Static layout wrapper component: Using a normal component (one or more slots containing different parts of the layout) as a wrapper for the view provides great flexibility and does not feel as dirty as the conditional rendering method.
// 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>
Copy the code
- Description:
- The home.vue component implements the LayoutDefault wrapper component to wrap its contents.
- While this approach has everything we need in terms of flexibility, wrapping our view in a static layout component has a huge disadvantage: Each time the route changes, the component is destroyed and recreated.
- Not only does this have a negative impact on performance, because the client has to recreate the layout component (and all the other components nested within it) again and again with every routing change, but it also means that you have to get some data for every path change you use in one of the components of the layout.
- Static layout wrapper components are powerful and flexible, but they also come with costs. Let’s see if we can come up with an approach that has all the positive features of a static wrapper component, but none of the negative, that would be the best solution
- Dynamically layout wrapper components
- Before we begin, let’s introduce a very powerful dynamic component of the component system in vue.js
<component :is="SomeComponent"/>
Copy the code
- In the example above, SomeComponent is a variable that can be dynamically assigned to any component, and each time a different component is assigned, the template renders the new component where you defined the tag.
- We can use dynamic components to build a very flexible and high-performance dynamic layout system. The code is as follows:
// 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>Copy the code
- You can see above that we no longer wrap the Layout view template in the LayoutDefault component, but we load the component and emit it as the new value of the Layout property we defined in the App base component. This means that once the Home component is created, the dynamic component that wraps the rendering Home component will be rerendered to render the component we emitted in the Created () hook.
- Why is this better than static wrapper components? The main difference is that the layout component is not part of the router view component, but wraps around it. This means that if the view component uses a different layout than the previous view component, only the layout component == is rerendered.
- Continuing to refactor the code makes using dynamic layout more intuitive
// Modify 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]; }}; <templatCopy the code
Refer to the link
- Dynamic vue.js layout components
- Github source address
- Demo — Demo address