Vue Router loads different components according to background data

Vue Router loads different components according to background data

Requirements encountered in actual projects

The same link needs to load different page components. Different pages are displayed depending on the services purchased by the user.

There are some bad implementations

  • Simply write these components under the same component and judge them through v-if. If you do this, you don't even need to use vue-router. You can just write all the components in one file and use v-if to judge them all. (The premise is that there are tens of thousands of lines of code together, if you don't mind the trouble)
  • When rendering this link, directly request the background data and render different links based on the data. (It is theoretically feasible, but if the user does not use this function, these links will fetch the background data in advance each time; in addition, if the user knows the link and directly accesses the link, logic is still needed to determine which page the user should see)
  • By calling router.beforeEach, each route is intercepted. When the route is the route we specify, the background data is requested and the page is jumped dynamically. (The function can be completed, but in fact, this is only a small part of the entire system and should not invade the entire routing system. If each business page is written in the global routing system, it will also cause the routing logic to be too complicated.)

I personally feel that the better way to implement

Get server data where the route is configured and dynamically load the corresponding components

{
  path: 'shopKPI',
  // If you save the background data to the store in advance, you can directly judge it by accessing the store data here // But the data of this specific business page is placed in the global store and is not used anywhere else, so it is really unnecessary component: () => import('@/views/store/dataVersion'),
  name: 'store_KPI',
  menuName: 'Shop Consultant',
  meta: {
    codes: ['storeProduct.detail']
  }
}

The ideal is beautiful, but the reality is that the method received by the component must return a promise synchronously.

At this time, I thought of the bad implementation method 1 above and modified it slightly.

<!-- ChooseShopKPI.vue -->
<template>
  <dataVersion v-if="!useNewShopKPI" />
  <ShopKPI v-else />
</template>

<script>
import { get } from 'lodash';
import { getStoreReportFormVersion } from '@/api/store';
import dataVersion from './dataVersion';
import ShopKPI from './ShopKPI';

export default {
  name: 'ChooseShopKPI',

  components:
    dataVersion,
    ShopKPI,
  },

  data() {
    return { useNewShopKPI: false };
  },

  created() {
    getStoreReportFormVersion().then((res) => {
      if (get(res, 'data.data.new')) {
        this.useNewShopKPI = true;
      }
    });
  },
};
</script>

<style lang="css" scoped></style>

Change the page corresponding to the route rendering to render this intermediate page ChooseShopKPI

{
  path: 'shopKPI',
  // If you get the background data in advance, you can directly judge it by accessing the store data here // But the data of this specific business page is placed in the global store and is not used anywhere else, so it is really unnecessary - component: () => import('@/views/store/dataVersion'),
+ component: () => import('@/views/store/ChooseShopKPI'),
  name: 'store_KPI',
  menuName: 'Shop Consultant',
  meta: {
    codes: ['storeProduct.detail']
  }
}

This achieves the functionality we expect.

The function has been realized, but I started to think about it again

Although this method solves the problem of dynamically loading page components very well. But some minor problems also arose.

  • If more pages that load data through the server are added later, multiple ChooseXXX intermediate pages will appear.
  • This kind of intermediate page actually performs secondary routing. Developers who are not familiar with the logic may not be clear about the page jump logic here, which increases the cost of understanding.

The final solution - high-level components

By abstracting ChooseXXX, transform it into DynamicLoadComponent

<!-- DynamicLoadComponent.vue -->
<template>
  <component :is="comp" />
</template>

<script>
export default {
  name: 'DynamicLoadComponent',
  props: {
    renderComponent: {
      type: Promise,
    },
  },
  data() {
    return {
      comp: () => this.renderComponent
    }
  },
  mounted() {},
};
</script>

<style lang="css" scoped></style>

Get the background data directly in the routing configuration and distribute the routes. In this way, the routing logic is concentrated in the routing configuration file, and there is no secondary routing. Maintenance won’t be a headache.

The DynamicLoadComponent component can also be reused, and any subsequent routing configurations for determining the background data loading page can be directed to this intermediate component.

{
  path: 'shopKPI',
  component: () => import('@/views/store/components/DynamicLoadComponent'),
  name: 'store_KPI',
  menuName: 'Shop Consultant',
  meta: {
    codes: ['storeProduct:detail'],
  },
  props: (route) => ({
    renderComponent: new Promise((resolve, reject) => {
      getStoreReportFormVersion()
        .then((responseData) => {
          const useNewShopKPI = get(responseData, 'data.data.shop_do');
          const useOldShopKPI = get(
            responseData,
            'data.data.store_data_show'
          );

          if (useNewShopKPI) {
            resolve(import('@/views/store/ShopKPI'));
          } else if (useOldShopKPI) {
            resolve(import('@/views/store/dataVersion'));
          } else {
            resolve(import('@/views/store/ShopKPI/NoKPIService'));
          }
        })
        .catch(reject);
    }),
  })
}

View online example (only supports Chrome)
https://stackblitz.com/edit/vuejs-starter-jsefwq?file=index.js

This is the end of this article about Vue Router loading different components according to background data. For more information about Vue Router loading different components according to background data, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope you will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Detailed explanation of vue-router data loading and cache usage summary

<<:  Solution to ERROR 1054 (42S22) when changing password in MySQL 5.7

>>:  Detailed explanation of permission management commands in Linux (chmod/chown/chgrp/unmask)

Recommend

HTML optimization techniques you must know

To improve the performance of web pages, many dev...

Explanation of the usage scenarios of sql and various nosql databases

SQL is the main trunk. Why do I understand it thi...

The difference between HTML iframe and frameset_PowerNode Java Academy

Introduction 1.<iframe> tag: iframe is an i...

Specific usage instructions for mysql-joins

Table of contents Join syntax: 1. InnerJOIN: (Inn...

Install Python virtual environment in Ubuntu 18.04

For reference only for Python developers using Ub...

Detailed explanation of how to use join to optimize SQL in MySQL

0. Prepare relevant tables for the following test...

Content-type description, that is, the type of HTTP request header

To learn content-type, you must first know what i...

Vue implements accordion effect

This article example shares the specific code of ...

The practical process of login status management in the vuex project

Table of contents tool: Login scenario: practice:...

Vue state management: using Pinia instead of Vuex

Table of contents 1. What is Pinia? 2. Pinia is e...

Example code of setting label style using CSS selector

CSS Selectors Setting style on the html tag can s...

js to realize the production method of carousel

This article shares the specific code for js to r...

How to install nginx in docker and configure access via https

1. Download the latest nginx docker image $ docke...

JavaScript flow control (branching)

Table of contents 1. Process Control 2. Sequentia...