背景:我构建了一个标准的单个文件组件,该组件带有一个name
属性,并在应用程序的目录结构的不同位置进行查找,并提供了第一个与该名称匹配的组件。创建它是为了在我的Vue.js CMS(称为Resto)中允许“子主题化”。这与WordPress查找模板文件的原理类似,首先检查子主题位置,然后如果找不到则将其还原为父主题,等等。
用法:该组件可以这样使用:
<!-- Find the PageHeader component
in the current child theme, parent theme,
or base components folder --->
<theme-component name="PageHeader">
<h1>Maybe I'm a slot for the page title!</h1>
</theme-component>
我的目标:我想转换为功能组件,以免影响应用程序的渲染性能或在Vue开发工具中显示。看起来像这样:
<template>
<component
:is="dynamicComponent"
v-if="dynamicComponent"
v-bind="{ ...$attrs, ...$props }"
v-on="$listeners"
@hook:mounted="$emit('mounted')"
>
<slot />
</component>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
name: 'ThemeComponent',
props: {
name: {
type: String,
required: true,
default: '',
},
},
data() {
return {
dynamicComponent: null,
resolvedPath: '',
}
},
computed: {
...mapGetters('site', ['getThemeName']),
customThemeLoader() {
if (!this.name.length) {
return null
}
// console.log(`Trying custom theme component for ${this.customThemePath}`)
return () => import(`@themes/${this.customThemePath}`)
},
defaultThemeLoader() {
if (!this.name.length) {
return null
}
// console.log(`Trying default component for ${this.name}`)
return () => import(`@restoBaseTheme/${this.componentPath}`)
},
baseComponentLoader() {
if (!this.name.length) {
return null
}
// console.log(`Trying base component for ${this.name}`)
return () => import(`@components/Base/${this.name}`)
},
componentPath() {
return `components/${this.name}`
}, // componentPath
customThemePath() {
return `${this.getThemeName}/${this.componentPath}`
}, // customThemePath()
},
mounted() {
this.customThemeLoader()
.then(() => {
// If found in the current custom Theme dir, load from there
this.dynamicComponent = () => this.customThemeLoader()
this.resolvedPath = `@themes/${this.customThemePath}`
})
.catch(() => {
this.defaultThemeLoader()
.then(() => {
// If found in the default Theme dir, load from there
this.dynamicComponent = () => this.defaultThemeLoader()
this.resolvedPath = `@restoBaseTheme/${this.defaultThemePath}`
})
.catch(() => {
this.baseComponentLoader()
.then(() => {
// Finally, if it can't be found, try the Base folder
this.dynamicComponent = () => this.baseComponentLoader()
this.resolvedPath = `@components/Base/${this.name}`
})
.catch(() => {
// If found in the /components dir, load from there
this.dynamicComponent = () => import(`@components/${this.name}`)
this.resolvedPath = `@components/${this.name}`
})
})
})
},
}
</script>
我已经尝试了许多不同的方法,但是我对功能组件和渲染函数还是比较陌生的。(从未涉足React)。
障碍:我似乎无法弄清楚如何运行在原始mounted()
函数中调用的链接函数。我尝试从render函数内部运行它,但没有成功。
在将组件传递给createElement
函数之前(或在我的单个文件<template functional><template/>
中),如何找到并动态导入要定位的组件?
感谢所有Vue-heads! ✌️
更新 :我偶然发现this solution使用了h()
渲染功能并随机加载了一个组件,但是我不确定如何使它能够接受name
道具...