基于 URL 参数动态导入 Vue 组件
Dynamically Import Vue Component Based On URL Params
我正在尝试根据 url 参数中输入的路径导入 vue 组件。因此,例如,如果在浏览器中输入 <host>/<path>
,我想导入一个位于 <path>.vue
.
的 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
有人知道如何实现吗?
我猜你正在使用 Webpack 来捆绑你的应用程序并解析 JS 模块。正如您在文档 https://webpack.js.org/api/module-methods/#import-1、import()
returns 中看到的承诺,它是异步工作的。在使用该组件之前,您必须先解决该承诺。
methods: {
async getComponentFile() {
const component = await this.importComponent(this.componentPath);
return component;
}
},
不难易解!
<component :is="componentFile" />
export default {
name: 'BaseObject',
components: {
firstComponent: () => import('...'),
secondComponent: () => import('...'),
thirdComponent: () => import('...')
}
computed: {
componentFile () {
return this.detectComponentBasedPath()
}
},
methods: {
detectComponentBasedPath () {
...
}
}
}
</script>
您的代码至少有 2 个问题...
你的“catch all”路线被定义为{ path: 'object/:catchAll(.*)*', component: BaseObject }
所以如果你导航到URLhttp://localhost:8080/#/object/action
“对象”部分匹配并且catchAll
param 将是一个包含单个项目“action”的数组。所以 created
钩子将弹出这个单个项目,params
数组保持为空并且 componentPath
也将为空(这是 Cannot find module './.vue'
错误的原因)
在 Vue 3 中,旧的异步组件语法 (() => import(``./${path}.vue``)
) is deprecated。创建异步组件时,您应该始终使用 defineAsyncComponent
帮助程序(这是 Invalid VNode type: undefined
Vue 警告的原因)
所以你 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>
另请注意,像这样定义“捕获所有”路由是危险的,因为它将匹配所有路由 - /object/action
、/object/action/dd
、/object/action/dd/bb
等,而这些组件不会存在。所以也许只允许一层嵌套会更好...
我正在尝试根据 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
有人知道如何实现吗?
我猜你正在使用 Webpack 来捆绑你的应用程序并解析 JS 模块。正如您在文档 https://webpack.js.org/api/module-methods/#import-1、import()
returns 中看到的承诺,它是异步工作的。在使用该组件之前,您必须先解决该承诺。
methods: {
async getComponentFile() {
const component = await this.importComponent(this.componentPath);
return component;
}
},
不难易解!
<component :is="componentFile" />
export default {
name: 'BaseObject',
components: {
firstComponent: () => import('...'),
secondComponent: () => import('...'),
thirdComponent: () => import('...')
}
computed: {
componentFile () {
return this.detectComponentBasedPath()
}
},
methods: {
detectComponentBasedPath () {
...
}
}
}
</script>
您的代码至少有 2 个问题...
你的“catch all”路线被定义为
{ path: 'object/:catchAll(.*)*', component: BaseObject }
所以如果你导航到URLhttp://localhost:8080/#/object/action
“对象”部分匹配并且catchAll
param 将是一个包含单个项目“action”的数组。所以created
钩子将弹出这个单个项目,params
数组保持为空并且componentPath
也将为空(这是Cannot find module './.vue'
错误的原因)在 Vue 3 中,旧的异步组件语法 (
() => import(``./${path}.vue``)
) is deprecated。创建异步组件时,您应该始终使用defineAsyncComponent
帮助程序(这是Invalid VNode type: undefined
Vue 警告的原因)
所以你 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>
另请注意,像这样定义“捕获所有”路由是危险的,因为它将匹配所有路由 - /object/action
、/object/action/dd
、/object/action/dd/bb
等,而这些组件不会存在。所以也许只允许一层嵌套会更好...