zoukankan      html  css  js  c++  java
  • Vue Router根据后台数据加载不同的组件(思考->实现->不止于实现)

    实际项目中遇到的需求

    同一个链接需要加载不同的页面组件。根据用户所购买服务的不同,有不同的页面展现。

    有一些不好的实现方式

    1. 直接把这几个组件写在同一个组件下,通过v-if去判断。如果这么做的话,甚至可以不使用vue-router,直接把所有组件,都写在一个文件里面,全部通过v-if判断,也是可行的。(前提是几万行代码一起,你不嫌麻烦的话)
    2. 在渲染这个链接的时候,直接去请求后台的数据,通过数据渲染不同的链接。(理论上是可行的,但如果用户没有用这个功能,这些链接每次都提前取了后台数据;另外如果用户知道了链接,直接访问链接,还是需要逻辑去判断用户该看到哪个页面)
    3. 通过调用router.beforeEach,对每个路由进行拦截,当路由为我们指定的路由时,请求后台数据,动态跳转页面。(功能是可以完成,但实际上,这只是整个系统的一小块功能,不应该侵入整个路由系统,如果每个业务页面,都写在全局路由系统,也会导致路由的逻辑过于复杂)

    个人感觉比较好的实现方式

    在配置路由的地方获取服务器数据动态加载对应的组件

    {
      path: 'shopKPI',
      // 如果提前把后台数据存到store里面,在这里访问store数据,可以直接判断出来
      // 但这种特定业务页面的数据放全局store,其他地方也不用,实在没有必要
      component: () => import('@/views/store/dataVersion'),
      name: 'store_KPI',
      menuName: '店铺参谋',
      meta: {
        codes: ['storeProduct.detail']
      }
    }
    

    理想很美好,现实的情况是,component接收的这个方法必须要同步的返回一个promise。

    这时候我想到了上面不好的实现方式1,稍微加以改造

    <!-- 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>
    

    把路由渲染对应的页面,改为渲染这个中间页面ChooseShopKPI

    {
      path: 'shopKPI',
      // 如果提前把后台数据取到,在这里访问store数据,可以直接判断出来
      // 但这种特定业务页面的数据放全局store,其他地方也不用,实在没有必要
    -  component: () => import('@/views/store/dataVersion'),
    +  component: () => import('@/views/store/ChooseShopKPI'),
      name: 'store_KPI',
      menuName: '店铺参谋',
      meta: {
        codes: ['storeProduct.detail']
      }
    }
    

    这样就实现了我们期望的功能。

    功能已实现,但我又开始了新的思考

    这种方式虽然很好的解决了动态加载页面组件的问题。但也产生了一些小问题。

    1. 如果这种通过服务器加载数据的页面后续增加的话,会出现多个ChooseXXX的中间页面。
    2. 这种中间页面,实际上是做了二次路由,不熟悉逻辑的开发人员可能并不清楚这里面的页面跳转逻辑,增加了理解成本。

    最终方案——高阶组件

    通过对ChooseXXX进行抽象,改造为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>
    
    

    直接在路由的配置中获取后台数据,并进行路由的分发。这样路由逻辑都集中在路由配置文件中,没有二次路由。维护起来不会头疼脑胀。

    DynamicLoadComponent组件也得以复用,后续新增判断后台数据加载页面的路由配置,都可以导向这个中间组件。

    {
      path: 'shopKPI',
      component: () => import('@/views/store/components/DynamicLoadComponent'),
      name: 'store_KPI',
      menuName: '店铺参谋',
      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);
        }),
      })
    }
    
    

    查看在线小例子(只支持chrome)
    https://stackblitz.com/edit/vuejs-starter-jsefwq?file=index.js

  • 相关阅读:
    Linq的Except
    BZOJ 1324 Exca神剑 最小割
    先学习Oracle 11g的Automatic Diagnostic Repository新功能
    NYOJ 300 &amp;&amp; hdu 2276 Kiki &amp; Little Kiki 2 (矩阵高速功率)
    V微软S2015下载:开展Win10/Linux/iOS多平台软件
    LeetCode Length of Last Word
    QT 打开文件对话框汇总
    取缔Chrome装载电脑管家的广告过滤脚本代码
    三种常见的图像处理双三次插值算法
    Best Time to Buy and Sell Stock I,II,III [leetcode]
  • 原文地址:https://www.cnblogs.com/zhea55/p/15115555.html
Copyright © 2011-2022 走看看