Requirements encountered in the actual project
The same link needs to load different page components . According to the different services purchased by users , There are different pages to show .
There are some bad implementations
- Write these components directly under the same component , adopt v-if To judge . If you do , You can not even use vue-router, Just put all the components , All in one file , All pass v-if Judge , It's also possible .( The premise is that tens of thousands of lines of code together , If you don't mind the trouble )
- When rendering this link , Directly request background data , Render different links through data .( It's theoretically possible , But if the user doesn't use this function , These links get the background data in advance every time ; In addition, if the user knows the link , Direct access link , You still need logic to determine which page users should see )
- By calling
router.beforeEach
, Intercept each route , When the route is the route we specify , Request background data , Dynamic jump page .( The function can be completed , But actually , This is just a small part of the whole system , Should not invade the entire routing system , If every business page , All written in the global routing system , It will also cause the logic of routing to be too complex )
I think it's a better way to realize
Get the server data at the place where the route is configured and dynamically load the corresponding components
{
path: 'shopKPI',
// If you save the background data to store Inside , Visit here store data , It can be judged directly
// However, the data of this specific business page is placed globally store, Not anywhere else , There's really no need
component: () => import('@/views/store/dataVersion'),
name: 'store_KPI',
menuName: ' Shop staff ',
meta: {
codes: ['storeProduct.detail']
}
}
The ideal is very good , The reality is ,component
The received method must synchronously return a promise.
Then I thought of the top Bad way to achieve 1, A little transformation
<!-- 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>
Render the route to the corresponding page , Instead, render the middle page ChooseShopKPI
{
path: 'shopKPI',
// If you get the background data to , Visit here store data , It can be judged directly
// However, the data of this specific business page is placed globally store, Not anywhere else , There's really no need
- component: () => import('@/views/store/dataVersion'),
+ component: () => import('@/views/store/ChooseShopKPI'),
name: 'store_KPI',
menuName: ' Shop staff ',
meta: {
codes: ['storeProduct.detail']
}
}
In this way, we achieve the desired function .
The function has been realized , But I started thinking again
Although this method solves the problem of dynamically loading page components . But there are also some small problems .
- If this page that loads data through the server is added later , There will be multiple
ChooseXXX
The middle page of . - This intermediate page , Actually did Secondary routing , Developers who are not familiar with logic may not know the page Jump logic , It increases the cost of understanding .
Final plan —— High order component
Through to ChooseXXX
Abstraction , Transform 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 route . In this way, the routing logic is concentrated in the routing configuration file , No secondary routing . No headache and brain swelling in maintenance .
DynamicLoadComponent
Components can also be reused , Subsequently, the routing configuration of the background data loading page is determined , Can lead to this intermediate component .
{
path: 'shopKPI',
component: () => import('@/views/store/components/DynamicLoadComponent'),
name: 'store_KPI',
menuName: ' Shop staff ',
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);
}),
})
}