Vue js动态导入组件

时间:2019-09-24 12:39:32

标签: javascript vue.js vuejs2 vue-component

我有以下父组件,该父组件必须呈现动态子组件的列表:

<template>
  <div>
    <div v-for="(componentName, index) in supportedComponents" :key="index">
      <component v-bind:is="componentName"></component>
    </div>
   </div>
 </template>

<script>
const Component1 = () => import("/components/Component1.vue");
const Component2 = () => import("/components/Component2.vue");
export default {
  name: "parentComponent",
  components: {
    Component1,
    Component2
  },
  props: {
    supportedComponents: {
      type: Array,
      required: true
    }
  }
};
</script>

supportedComponents属性是我要在父组件中呈现的组件名称的列表。

为了在父级中使用子级组件,我必须导入它们并注册它们。

但是唯一的方法是对组件的导入路径进行硬编码:

const Component1 = () => import("/components/Component1.vue");
const Component2 = () => import("/components/Component2.vue");

然后像这样注册它们:

components: {
  Component1,
  Component2
}

我想让我的parentComponent尽可能通用。这意味着我必须找到一种方法来避免在导入语句和注册时使用硬编码的组件路径。我想在parentComponent中注入应该导入和呈现的子组件。

在Vue中这可能吗?如果是,那怎么办?

5 个答案:

答案 0 :(得分:0)

您可以在Vue中注册组件,然后仅在全局范围内使用它们而无需导入或注册。

yourMain.js:

const Component1 = () => import("/components/Component1.vue");
const Component2 = () => import("/components/Component1.vue");


Vue.component('Component1', Component1);
Vue.component('Component2', Component1);

YourComponent.vue

<template>
 <div> 
    <Component1 />
    <Component2 />
 </div>
</template>

https://vuejs.org/v2/guide/components-registration.html

答案 1 :(得分:0)

在运行时解析动态Webpack import()

您可以动态设置import()函数的路径,以根据组件状态加载不同的组件。

<template>
  <component :is="myComponent" />
</template>

<script>
export default {
  props: {
    component: String,
  },

  data() {
    return {
      myComponent: '',
    };
  },

  computed: {
    loader() {
      return () => import(`../components/${this.component}`);
    },
  },

  created() {
    this.loader().then(res => {
      // components can be defined as a function that returns a promise;
      this.myComponent = () => this.loader();
    },
  },
}
</script>

注意:JavaScript是在您运行之前由您的浏览器编译的。这与解决webpack导入无关。

答案 2 :(得分:0)

您可以在创建的生命周期内加载组件并根据您的array属性对其进行注册:

<template>
    <div>
        <div v-for="(componentName, index) in supportedComponents" :key="index">
            <component :is="componentName"></component>
        </div>
    </div>
</template>

<script>
    export default {
        name: "parentComponent",
        components: {},
        props: {
            supportedComponents: {
                type: Array,
                required: true
            }
        },
        created ()  {
            for(let c=0; c<this.supportedComponents.length; c++) {
                let componentName = this.supportedComponents[c];
                this.$options.components[componentName] = () => import('./' + componentName + '.vue');
            }
        }
    };
</script>

效果很好

答案 3 :(得分:0)

这是一个有效的代码,只要确保你的动态导入中有一些字符串,否则你会得到“找不到模块”

       <component :is="current" />
    export default {  data () {
    return {
      componentToDisplay: null
    }
  },
  computed: {
    current () {
      if (this.componentToDisplay) {
        return () => import('@/components/notices/' + this.componentToDisplay)
      }
      return () => import('@/components/notices/LoadingNotice.vue')
    }
  },
  mounted () {
    this.componentToDisplay = 'Notice' + this.$route.query.id + '.vue'
  }
}

答案 4 :(得分:0)

我认为我们需要一些可以有代码并且每次都应该自动加载的插件。这个解决方案对我有用。

import { App, defineAsyncComponent } from 'vue'
const componentList = ['Button', 'Card']
export const registerComponents = async (app: App): void => {
  // import.meta.globEager('../components/Base/*.vue')
  componentList.forEach(async (component) => {
    const asyncComponent = defineAsyncComponent(
      () => import(`../components/Base/${component}.vue`)
    )
    app.component(component, asyncComponent)
  })
}

你也可以试试 glob,它也能很好地工作,但我已经检查过这个解决方案,但值得一读

Dynamic import

[更新]

我对 import.meta.globEage 进行了同样的尝试,但它的工作原理是稍微延迟加载,您可能会觉得它加载缓慢但并不明显。

import { App, defineAsyncComponent } from 'vue'
export const registerComponents = async (app: App): void => {
Object.keys(import.meta.globEager('../components/Base/*.vue')).forEach(
    async (component) => {
    const asyncComponent = defineAsyncComponent(
        () => import(/* @vite-ignore */ component)
    )
    app.component(
        (component && component.split('/').pop()?.split('.')[0]) || '',asyncComponent
    )
    })
}