Vue-动态导入vue组件

deyfvvtc  于 2022-12-30  发布在  Vue.js
关注(0)|答案(6)|浏览(273)

我有很多组件,我想按需导入。我有一个下拉列表,其中实际上包含组件列表,这是什么加载。我尝试了这个例子

<component :is="componentLoader"></component>

在脚本中

componentLoader () {
  return () => import('@/components/testDynamic') 
}
    • testDynamic**是一个组件名(目前我尝试使用静态组件)。

获取此错误

GET http://localhost:8080/0.js net::ERR_ABORTED 404
[Vue warn]: Failed to resolve async component: function () {
    return __webpack_require__.e/* import() */(0).then(__webpack_require__.bind(null, "./src/components/testDynamic.vue"));
  }
  Reason: Error: Loading chunk 0 failed.

如何解决这个问题?我做错了什么吗?或者有没有其他方法来动态导入组件?

8i9zcol2

8i9zcol21#

可以在单个文件组件中本地注册异步动态组件,如下所示:

export default {
  components: {
    'test-dynamic': () => import('@/components/testDynamic'),
    'other-dynamic': () => import('@/components/otherDynamic')
  },
  data () {
    return {
      current: 'test-dynamic'
    }
  }
}

在您的模板中:

<component :is="current"></component>

如果注册多个组件,则只需将current的值更改为所需的组件。
对于许多组件,可以导入一个对象,将组件名称Map到其各自的文件路径,然后按如下方式注册它们:

import myComponents from '@/components'

export default {
  components: Object.keys(myComponents).reduce((obj, name) => {
    return Object.assign(obj, { [name]: () => import(myComponents[name]) })
  }, {})
  ...
}

其中myComponents导出为:

// components/index.js
export default {
  foo: '@/path/to/Foo',
  bar: '@/path/to/Bar',
  ...
}
bq8i3lrv

bq8i3lrv2#

我遇到了同样的问题,因为我使用的是Vue 3,这里给出的解决方案对我都不起作用。经过一番研究,我发现定义动态组件(异步组件)的过程在Vue 3中略有不同。我希望这段代码能对大家有所帮助。

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

<script>
//Vue 3 is having a special function to define these async functions
import {defineAsyncComponent} from "vue";

export default {
 name: "DynamicComponent",
 //I am passing the name of the Component as a prop
 props: {
     componentName:{
         type: String,
         required: true
     }
 },
 computed: {
  comp () {
      return defineAsyncComponent(() => import(`@/components/${this.componentName}.vue`))
  }
}
}
</script>
o4hqfura

o4hqfura3#

我经常使用下面的方法(Vue 2),效果很好。
下面的简单示例允许动态指定要加载的组件:- 因为调用launchEditForm只需要一个字符串作为参数,如果你可以将文件名表示为字符串,那么你就可以加载它。
保持launchEditForm为“计算”属性非常重要,即不要在“方法”中定义它。
如果您调用的文件不存在,则会出现如下所示的运行时错误:找不到模块“./components/cliente/forms/不存在.vue”

<template>
  <div>
    <button
      type="button"
@click="launchEditForm('components/clients/forms/EditContactsForm.vue')"
    >
      Edit Contacts
    </button>
    <component :is="currentEditForm" />
  </div>
</template>
<script>
export default {
  name: 'Screen42',
  data() {
    return {
      componentToDisplay: null
    };
  },
  computed: {
    currentEditForm: function() {
      if (this.componentToDisplay) {
        return () => import(`@/${this.componentToDisplay}`);
      }
      return null;
    }
  },
  methods: {
    launchEditForm(fileName) {
      this.componentToDisplay = fileName;
    }
  }
};
</script>

请注意,在上面的示例中,该文件位于.../src/components/clients/forms/EditContactsForm.vue
通常这种类型的动态导入是在模态中完成的,它只是在模态中移动标签的一种情况。显然我们可以使用带有布尔变量的v-if来打开和关闭模态。但是上面的代码应该说明核心点-即组件名称可以动态生成,组件可以动态加载。

55ooxyrt

55ooxyrt4#

对我起作用的是等待componentLoader函数,因为import函数返回一个承诺!

async componentLoader () {
  return await import('@/components/testDynamic') 
}
qnakjoqk

qnakjoqk5#

对于VUE 3合成API,在更新lifecycle之前使用defineasynccomponent和一个挂接
示例将组件作为 prop 传递

....
//need two components for substitute your desired component 
import  LoadingComponent from "~/components/LoadingComponent.vue"
import  ErrorComponent from "~/components/ErrorComponent.vue"
...
// we get component name from the props
const props = defineProps<{ 
  componentName: string 
    }>()
//define the const to mount our component as ref so we can change //his value
const comp = shallowRef()

comp.value = defineAsyncComponent({
  // the loader function
  loader: () => import(`../../components/${props.componentName}.vue`),
 // A component to use while the async component is loading
  loadingComponent: LoadingComponent,
 // Delay before showing the loading component. Default: 200ms.
  delay: 200,
 // A component to use if the load fails
  errorComponent: ErrorComponent,
  // The error component will be displayed if a timeout is
  // provided and exceeded. Default: Infinity.
  timeout: 3000 ,
  suspensible : false,
  onError(error, retry, fail, attempts) {
     if (error.message.match(/fetch/) && attempts <= 3) {
       retry();
     } else {
       fail();
     }
  }
})

onBeforeUpdate(()=>{
  comp.value = defineAsyncComponent(() => import(`../../components/${props.componentName}.vue`))
})

...
//then on <template> just use 
<component  :is="comp" ></component>

如果你不想在控制台上的消息抱怨你可以跟随errorhandler

dpiehjr4

dpiehjr46#

下面是Brian Lee对答案的扩展,包括额外的UX覆盖范围和Webpack优化:

<template>
  <AssetMedia
    v-if="assetToEdit.typeOfAsset === 'social'"
    :key="assetToEdit.id"
    :assetOfInterest="assetToEdit" />
</template>

<script>
// Components.
import AppErrorComponent from '../../application/Error'
import AppLoadingComponent from '../../application/Loading'
export default {
  name: 'AssetEdit',
  components: {
    AssetMedia: () => ({
      component: import(/* webpackChunkName: "AssetMedia" */ './features/AssetMedia'),
      loading: AppLoadingComponent,
      error: AppErrorComponent,
      timeout: 3000
    })
  }
}

这里,v-if可以是取决于assetToEdit的成功加载的某个布尔参数。

相关问题