Skip to content

子组件同步异步引入问题

目前页面都是组件化开发,对于页面使用到的子组件存在同步引入与异步引入的问题,不同的引入方式会影响页面对子组件的使用,建议都采用同步引入的方式来引入子组件。

子组件异步引用的问题

  • TODO:页面使用到的子组件,如果是异步引入,子组件最终会编译程一个单独的JS文件,此处直接通过refs直接调用子组件的时候,由于子组件文件可能没有加载完成,可能存在获取子组件示例为空的情况
vue
<!-- 门户首页 -->
<template>
  <!-- 容器 -->
  <component ref="component" :is="activeComponent" />
</template>
<script>
import { mapGetters } from 'vuex';
import { GET_LAYOUT } from '@/store/login';
import { LAYOUT } from '@/assets/js/constant';

export default {
  name: 'INDEX',
  // TODO:页面使用到的子组件全部是异步引入
  components: {
    vDefault: () =>
      import(
        /* webpackChunkName: 'src/modules/home/index/default/index' */ '@/modules/home/index/default/index'
      ),
    vAdmin: () =>
      import(
        /* webpackChunkName: 'src/modules/home/index/admin/index' */ '@/modules/home/index/admin/index'
      ),
    vPoliceOfficer: () =>
      import(
        /* webpackChunkName: 'src/modules/home/index/police-officer/index' */ '@/modules/home/index/police-officer/index'
      ),
    vEfmPur: () =>
      import(
        /* webpackChunkName: 'src/modules/home/index/efm-pur/index' */ '@/modules/home/index/efm-pur/index'
      ),
    vIntegrationHb: () =>
      import(
        /* webpackChunkName: 'src/modules/home/index/integration-hb/index' */ '@/modules/home/index/integration-hb/index'
      ),
  },
  data() {
    return {
      open: false,
    };
  },
  beforeRouteEnter(to, from, next) {
    next((vm) => {
      vm.onBeforeRouteEnter();
    });
  },
  methods: {
    /**
     * 处理路由进入
     * 1、如果页面打开过,切包含更新数据的方法,则需要更新页面
     */
    onBeforeRouteEnter() {
      if (this.open) {
        // TODO:页面使用到的子组件,如果是异步引入,此处直接通过refs直接调用子组件的时候,由于子组件可能没有加载完成,此处存在获取子组件示例为空的情况
        let el = this.$refs.component;
        _.isFunction(el.updatePage) && el.updatePage();
      }
      this.open = true;
    },
  },
  computed: {
    ...mapGetters([GET_LAYOUT]),
    /**
     * 当前激活的组件
     * 1、根据当前系统布局返回不同的组件
     * 2、警务传统布局也返回vDefault组件
     * 3.采购档案
     */
    activeComponent() {
      switch (this.GET_LAYOUT) {
        case LAYOUT.ADMIN:
          return 'vAdmin';
        case LAYOUT.POLICE_OFFICER:
          return 'vPoliceOfficer';
        case LAYOUT.EFM_PUR:
          return 'vEfmPur';
        case LAYOUT.INTEGRATION_HUBEI:
          return 'vIntegrationHb';
        default:
          return 'vDefault';
      }
    },
  },
};
</script>

子组件同步引用示例

  • 页面在使用子组件时,如果子组件是同步引用的,由于编译时,子组件代码会与页面编译程一个JS文件,所以就不存在子组件文件没有加载完成的情况了。
vue
<!-- 门户首页 -->
<template>
  <!-- 容器 -->
  <component ref="component" :is="activeComponent" />
</template>
<script>
import { mapGetters } from 'vuex';
import { GET_LAYOUT } from '@/store/login';
import { LAYOUT } from '@/assets/js/constant';
// TODO:页面使用到的子组件都同步引用
import vDefault from '@/modules/home/index/default/index';
import vAdmin from '@/modules/home/index/admin/index';
import vPoliceOfficer from '@/modules/home/index/police-officer/index';
import vEfmPur from '@/modules/home/index/efm-pur/index';
import vIntegrationHb from '@/modules/home/index/integration-hb/index';
export default {
  name: 'INDEX',
  data() {
    return {
      open: false,
    };
  },
  beforeRouteEnter(to, from, next) {
    next((vm) => {
      vm.onBeforeRouteEnter();
    });
  },
  methods: {
    /**
     * 处理路由进入
     * 1、如果页面打开过,切包含更新数据的方法,则需要更新页面
     */
    onBeforeRouteEnter() {
      if (this.open) {
        let el = this.$refs.component;
        _.isFunction(el.updatePage) && el.updatePage();
      }
      this.open = true;
    },
  },
  computed: {
    ...mapGetters([GET_LAYOUT]),
    /**
     * 当前激活的组件
     * 1、根据当前系统布局返回不同的组件
     * 2、警务传统布局也返回vDefault组件
     * 3.采购档案
     */
    activeComponent() {
      switch (this.GET_LAYOUT) {
        case LAYOUT.ADMIN:
          return vAdmin;
        case LAYOUT.POLICE_OFFICER:
          return vPoliceOfficer;
        case LAYOUT.EFM_PUR:
          return vEfmPur;
        case LAYOUT.INTEGRATION_HUBEI:
          return vIntegrationHb;
        default:
          return vDefault;
      }
    },
  },
};
</script>