首页 > 解决方案 > 基于 URL 参数动态导入 Vue 组件

问题描述

我正在尝试根据输入 url 参数的路径导入 vue 组件。因此,例如,如果<host>/<path>在浏览器中输入,我想导入一个位于<path>.vue.

在我的routes.js文件中,我有一条将获得嵌套路径的路线:

  { path: 'object/:catchAll(.*)*', component: BaseObject }

并将其发送至BaseObject

<template>
  <div>
    <component :is="componentFile" />
  </div>
</template>
<script>
import { mapState, mapActions } from 'vuex'

export default {
  name: 'BaseObject',
  data () {
    return {
      componentPath: '',
      address: ''
    }
  },
  methods: {
    importComponent (path) {
      return () => import(`./${path}.vue`)
    }
  },
  computed: {
    componentFile () {
      return this.importComponent(this.componentPath)
    }
  },
  created () {
    const params = this.$route.params.catchAll
    console.log(params)
    this.address = params.pop()
    this.componentPath = params.join('/')
  }
}
</script>

当我导航到 时http://localhost:8080/#/object/action,我希望./action.vue加载位于的组件。但这不会发生 - 相反,我收到以下错误:

runtime-core.esm-bundler.js?9e79:38 [Vue warn]: Invalid VNode type: undefined (undefined) 
  at <Anonymous> 
  at <BaseObject onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< null > > 
  at <RouterView> 
  at <QPageContainer> 
  at <QLayout view="lHh Lpr lFf" > 
  at <MainLayout onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy {$i18n: {…}, $t: ƒ, …} > > 
  at <RouterView> 
  at <App>

Uncaught (in promise) Error: Cannot find module './.vue'
        at app.js:416

有谁知道如何做到这一点?

标签: vue.jsroutesvue-componentvuejs3

解决方案


您的代码至少有两个问题...

  1. 您的“catch all”路由被定义为{ path: 'object/:catchAll(.*)*', component: BaseObject },如果您导航到 URL http://localhost:8080/#/object/action,则匹配“object”部分,catchAllparam 将是一个包含单个项目“action”的数组。所以created钩子会弹出这个单项,params数组保持为空并且componentPath也将是空的(这是Cannot find module './.vue'错误的原因)

  2. 在 Vue 3 中,旧的异步组件语法 ( () => import(``./${path}.vue``))已弃用。创建异步组件时应始终使用defineAsyncComponenthelper(这是Invalid VNode type: undefinedVue 警告的原因)

所以你BaseObject应该看起来像这样:

<template>
  <div>
    <component :is="componentFile" />
  </div>
</template>
<script>
import { defineComponent, defineAsyncComponent } from "vue";

export default defineComponent({
  name: "BaseObject",
  data() {
    return {
      componentPath: "",
      address: "",
    };
  },
  methods: {},
  computed: {
    componentFile() {
      return defineAsyncComponent(() =>
        import(`../components/${this.componentPath}.vue`)
      );
    },
  },
  created() {
    const params = this.$route.params.catchAll;
    console.log(this.$route.params);
    // this.address = params.pop();
    this.componentPath = params.join("/");
  },
});
</script>

工作演示

另请注意,像这样定义“catch all”路线是危险的,因为它会将所有路线匹配为 - /object/action、等/object/action/dd/object/action/dd/bb并且这些组件将不存在。所以也许只允许一层嵌套会更好......


推荐阅读