Предпосылки: Я создал стандартный компонент с одним файлом, который принимает name
опору и просматривает в разных местах структуру каталогов моего приложения и предоставляет первый сопоставленный компонент с этим именем. Он был создан, чтобы разрешить "дочернюю тематику" в моей Vue. js CMS, которая называется Resto. Это аналогично тому, как WordPress ищет файлы шаблонов, сначала проверяя расположение дочерней темы, а затем возвращаясь к родительской теме, если она не найдена, et c.
Использование : компонент можно использовать следующим образом:
<!-- 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()
. Я безуспешно пытался запустить его изнутри функции рендеринга.
Большой вопрос
Как мне найти и динамически импортировать компонент, на который я нацелен, прежде чем передать этот компонент в createElement
(или в моем единственном файле <template functional><template/>
)?
Спасибо всем вам, Vue -головы! ✌️
Обновление : я наткнулся на это решение для использования функции рендеринга h()
и случайной загрузки компонента, но я не уверен, как заставить его работать, чтобы принять name
prop ...