vue/quasar - 动态注入组件
vue/quasar - dynamically injecting components
我正在尝试找出一种方法来将 vue 组件动态加载到我的布局中,而无需实际专门导入它们。采取这种结构
// Directory structure
src/
layouts/
MainLayout.vue
modules/
client/
inject.ts
components/
AddButton.vue
property/
inject.ts
components/
AddButton.vue
boot/
injectors.ts
// modules/client/inject.ts (client/)
import {defineAsyncComponent} from "vue";
export default [
{
component: defineAsyncComponent(() => import('./components/AddButton.vue')),
id: 'client-add-button',
to: 'action-bar',
}
]
// modules/property/inject.ts
import {defineAsyncComponent} from "vue";
export default [
{
component: defineAsyncComponent(() => import('./components/AddButton.vue')),
id: 'property-add-button',
to: 'action-bar',
}
]
// boot/injectors.ts
export default boot(() => {
// Somehow loop through all folders in src/modules/ and find inject files
//
const injections = // concat the exported arrays into a single array
app.provide('$injections', injections);
});
// src/layouts/MainLayout.vue
<template>
<div>
<template v-for="comp in injected" :key="comp.id">
<component :is="comp.component" />
</template>
</div>
</template>
<script lang="ts">
import {
computed, defineComponent, ref,
} from 'vue';
export default defineComponent({
name: 'MainLayout',
setup() {
const injectables = computed( () => {
return $injections.filter( injection => injection.to === 'action-bar');
});
}
});
</script>
想法是“模块”不会污染全局 view/layout space,而是被赋予注入其中的能力。
我不知道的部分是让它变得动态。我不想不断地向“引导”文件中添加文件。我想用 inject.ts 个文件创建模块让它工作
我觉得必须在 Webpack 中而不是在“启动”模块中完成此动态,但我有 NFI 从这里开始
好的。这会很长,但我想通了。我需要创建一个扩展 - 我将其命名为 InjectMe。
// injectme/index.js
/**
* Quasar App Extension index/runner script
* (runs on each dev/build)
*
* Docs: https://quasar.dev/app-extensions/development-guide/index-api
* API: https://github.com/quasarframework/quasar/blob/master/app/lib/app-extension/IndexAPI.js
*/
path = require('path');
fs = require('fs');
const extendConf = async function (conf) {
console.log(' Starting InjectMe installation');
// make sure boot & component files transpile
conf.boot.push('~quasar-app-extension-injectme/src/boot/setup.ts');
conf.build.transpileDependencies.push(/quasar-app-extension-injectme[\/]src/);
const baseDir = 'src/modules/';
try {
const modules = await fs.promises.readdir(baseDir);
for (const file of modules) {
const filePath = path.join(baseDir, file);
// eslint-disable-next-line no-await-in-loop
const stat = await fs.promises.stat(filePath);
if (stat.isDirectory()) {
const moduleFiles = await fs.promises.readdir(filePath);
for (const moduleFile of moduleFiles) {
const moduleFilePath = path.join(filePath, moduleFile);
if (moduleFile.includes('inject.ts')) {
conf.boot.push('../../' + moduleFilePath);
conf.build.transpileDependencies.push(moduleFilePath);
console.log(` : InjectMe Installed ${moduleFilePath}`);
}
}
}
} // End for...of
} catch (e) {
console.error(e);
}
conf.boot.push('~quasar-app-extension-injectme/src/boot/provide.ts')
}
/**
* Quasar App Extension index/runner script
* (runs on each dev/build)
*
* Docs: https://quasar.dev/app-extensions/development-guide/index-api
* API: https://github.com/quasarframework/quasar/blob/master/app/lib/app-extension/IndexAPI.js
*/
module.exports = function (api) {
// extend quasar.conf
api.extendQuasarConf(extendConf)
}
// injectme/src/boot/setup.ts
import { boot } from 'quasar/wrappers';
export default boot( ({app}) => {
app.config.globalProperties.$injectme = [];
});
// injectme/src/boot/provide.ts
import { boot } from 'quasar/wrappers';
export default boot( ({app}) => {
app.provide('injectme', app.config.globalProperties.$injectme);
});
我将此扩展程序放置在我的类星体应用程序上方的几个目录中(因此我可以在本地安装而无需将其放在 NPM 存储库中)。
// Directory structure looks like this
extensions/
injectme/
src/
/boot
web/ # quasar app
src/
modules/
client/
现在在我的类星体应用程序中,我将扩展名添加到 package.json 文件:
"quasar-app-extension-injectme": "file:../extensions/injectme",
接下来我将扩展程序调用到应用程序中:
quasar ext invoke injectme
现在要加载动态模块,我需要在模块/文件夹中创建一个 inject.ts 文件
# web/src/modules/client/inject.ts
import { boot } from 'quasar/wrappers';
import { defineAsyncComponent } from 'vue';
import { routes } from './routes';
export default boot(({ app }) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
app.config.globalProperties.$injectme.push({
id: 'client-add-new-button',
component: defineAsyncComponent(() => import('./components/AddButton.vue')),
// Anything
to: 'action-bar',
});
);
现在,使用“quasar dev”重新加载应用程序,您应该会看到 injectme 拾取注入文件。
它现在将组件添加到全局 $injectme,然后作为“可注入”提供回 Vue。
因此,转到应用程序完全不同部分的新文件,然后对其进行测试。
// web/src/layout/MainLayout.vue
<template>
<div>
<template v-for="comp in components.filter(c => c.to === 'action-bar')" :key="comp.id">
<component :is="comp.component" />
</template>
</div>
</template>
<script lang="ts">
...
setup() {
const components = inject('injectme');
return { components };
}
</script>
好了。我还没有做过内存测试,也没有做过任何性能测试,所以这真的是你自己承担风险。
它实际上是为了在这里和那里添加按钮,而不是用于包含许多元素等的大型组件。
我正在尝试找出一种方法来将 vue 组件动态加载到我的布局中,而无需实际专门导入它们。采取这种结构
// Directory structure
src/
layouts/
MainLayout.vue
modules/
client/
inject.ts
components/
AddButton.vue
property/
inject.ts
components/
AddButton.vue
boot/
injectors.ts
// modules/client/inject.ts (client/)
import {defineAsyncComponent} from "vue";
export default [
{
component: defineAsyncComponent(() => import('./components/AddButton.vue')),
id: 'client-add-button',
to: 'action-bar',
}
]
// modules/property/inject.ts
import {defineAsyncComponent} from "vue";
export default [
{
component: defineAsyncComponent(() => import('./components/AddButton.vue')),
id: 'property-add-button',
to: 'action-bar',
}
]
// boot/injectors.ts
export default boot(() => {
// Somehow loop through all folders in src/modules/ and find inject files
//
const injections = // concat the exported arrays into a single array
app.provide('$injections', injections);
});
// src/layouts/MainLayout.vue
<template>
<div>
<template v-for="comp in injected" :key="comp.id">
<component :is="comp.component" />
</template>
</div>
</template>
<script lang="ts">
import {
computed, defineComponent, ref,
} from 'vue';
export default defineComponent({
name: 'MainLayout',
setup() {
const injectables = computed( () => {
return $injections.filter( injection => injection.to === 'action-bar');
});
}
});
</script>
想法是“模块”不会污染全局 view/layout space,而是被赋予注入其中的能力。
我不知道的部分是让它变得动态。我不想不断地向“引导”文件中添加文件。我想用 inject.ts 个文件创建模块让它工作
我觉得必须在 Webpack 中而不是在“启动”模块中完成此动态,但我有 NFI 从这里开始
好的。这会很长,但我想通了。我需要创建一个扩展 - 我将其命名为 InjectMe。
// injectme/index.js
/**
* Quasar App Extension index/runner script
* (runs on each dev/build)
*
* Docs: https://quasar.dev/app-extensions/development-guide/index-api
* API: https://github.com/quasarframework/quasar/blob/master/app/lib/app-extension/IndexAPI.js
*/
path = require('path');
fs = require('fs');
const extendConf = async function (conf) {
console.log(' Starting InjectMe installation');
// make sure boot & component files transpile
conf.boot.push('~quasar-app-extension-injectme/src/boot/setup.ts');
conf.build.transpileDependencies.push(/quasar-app-extension-injectme[\/]src/);
const baseDir = 'src/modules/';
try {
const modules = await fs.promises.readdir(baseDir);
for (const file of modules) {
const filePath = path.join(baseDir, file);
// eslint-disable-next-line no-await-in-loop
const stat = await fs.promises.stat(filePath);
if (stat.isDirectory()) {
const moduleFiles = await fs.promises.readdir(filePath);
for (const moduleFile of moduleFiles) {
const moduleFilePath = path.join(filePath, moduleFile);
if (moduleFile.includes('inject.ts')) {
conf.boot.push('../../' + moduleFilePath);
conf.build.transpileDependencies.push(moduleFilePath);
console.log(` : InjectMe Installed ${moduleFilePath}`);
}
}
}
} // End for...of
} catch (e) {
console.error(e);
}
conf.boot.push('~quasar-app-extension-injectme/src/boot/provide.ts')
}
/**
* Quasar App Extension index/runner script
* (runs on each dev/build)
*
* Docs: https://quasar.dev/app-extensions/development-guide/index-api
* API: https://github.com/quasarframework/quasar/blob/master/app/lib/app-extension/IndexAPI.js
*/
module.exports = function (api) {
// extend quasar.conf
api.extendQuasarConf(extendConf)
}
// injectme/src/boot/setup.ts
import { boot } from 'quasar/wrappers';
export default boot( ({app}) => {
app.config.globalProperties.$injectme = [];
});
// injectme/src/boot/provide.ts
import { boot } from 'quasar/wrappers';
export default boot( ({app}) => {
app.provide('injectme', app.config.globalProperties.$injectme);
});
我将此扩展程序放置在我的类星体应用程序上方的几个目录中(因此我可以在本地安装而无需将其放在 NPM 存储库中)。
// Directory structure looks like this
extensions/
injectme/
src/
/boot
web/ # quasar app
src/
modules/
client/
现在在我的类星体应用程序中,我将扩展名添加到 package.json 文件:
"quasar-app-extension-injectme": "file:../extensions/injectme",
接下来我将扩展程序调用到应用程序中:
quasar ext invoke injectme
现在要加载动态模块,我需要在模块/文件夹中创建一个 inject.ts 文件
# web/src/modules/client/inject.ts
import { boot } from 'quasar/wrappers';
import { defineAsyncComponent } from 'vue';
import { routes } from './routes';
export default boot(({ app }) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
app.config.globalProperties.$injectme.push({
id: 'client-add-new-button',
component: defineAsyncComponent(() => import('./components/AddButton.vue')),
// Anything
to: 'action-bar',
});
);
现在,使用“quasar dev”重新加载应用程序,您应该会看到 injectme 拾取注入文件。
它现在将组件添加到全局 $injectme,然后作为“可注入”提供回 Vue。
因此,转到应用程序完全不同部分的新文件,然后对其进行测试。
// web/src/layout/MainLayout.vue
<template>
<div>
<template v-for="comp in components.filter(c => c.to === 'action-bar')" :key="comp.id">
<component :is="comp.component" />
</template>
</div>
</template>
<script lang="ts">
...
setup() {
const components = inject('injectme');
return { components };
}
</script>
好了。我还没有做过内存测试,也没有做过任何性能测试,所以这真的是你自己承担风险。
它实际上是为了在这里和那里添加按钮,而不是用于包含许多元素等的大型组件。