繁体   English   中英

如何使用组合 API 全局注册 Vue 3 组件?

[英]How to globally register a Vue 3 component with the composition API?

我正在使用 Vue 3 和组合 API 创建组件库。组件库将作为插件加载到 NuxtJS 应用程序中。 在这个插件中全局注册组件(根据组合API编写)的正确方法是什么?

./stories/Panel.vue (极简版):

<template>
    <div class="panel">
        <div class="header" v-if="title">{{ title }}</div>
        {{ content }}
    </div>
</template>

<style>
.panel .header {
    background-color: #7f7f7f;
    color: #fff;
}
</style>

<script setup lang="ts">
interface Props {
    title?: string;
    content?: string;
}

const name = 'my-panel';
const props = defineProps<Props>();
</script>

components.ts (包含所有组件):

import Panel from './stories/Panel.vue';
// all other components are imported and exported as well

export {
    Panel
};

lib.ts

import * as components from './components';
import { App } from '@vue/runtime-core';

const plugin = {
    install(Vue: App) {
        Object.values(components).forEach((component) => {
            // Is there a way to globally register a component in a way
            // that the name, defined in the composition API is used?
            Vue.component(component);
        });
    },
};

export default plugin;

这是一个通用方法,有一些选项。 您可以根据最适合您的方式来决定具体细节。

原则

在普通<script>块中导出的变量可以单独导入到组件本身,并且在该脚本块中定义的任何内容在<script setup>块中也可用。

方法

组件

这些组件需要从常规<script>块中导出元数据。 您在这里有两个选择:直接导出名称(较少样板文件),或导出元数据 object(如果您需要的元数据不仅仅是名称,则推荐使用)。

只有一个名字:

Panel.vue

<script lang="ts">
export const name = "my-panel";
</script>

<script setup lang="ts">
console.log(name) // `name` is available here.
</script>

使用元数据 object:

Panel.vue

<script lang="ts">
export const metadata = {
  name: "my-panel",
};
</script>

<script setup lang="ts">
console.log(metadata.name) // `metadata` is available here.
</script>

指数

不幸的是,与原始部分相比,这部分非常冗长。

只是一个名字

名称必须以某种方式包含在导出中。 这将需要使用单个值的导出,因为我们不只是导出现有绑定(例如变量或导入的组件)。 由于在本例中它只是一个名称,因此可以使用带有计算属性键的简单 object。 如果需要,您还可以使用“元数据对象”部分中显示的“顶级数组”方法之一。

components.ts

// Import the metadata as well.
import Panel, { name as PanelName } from './stories/Panel.vue';

// The export can be default or named.
export default {
  [PanelName]: Panel,
}

元数据 object

如果只需要名称,可以使用上一节中的方法。

components.ts

// Import the metadata as well.
import Panel, { metadata as PanelMetadata } from './stories/Panel.vue';

// This works the same as in the previous section.
// As before, the export can be default or named.
export default {
  [PanelMetadata.name]: Panel,
}

但是,对于元数据 object,您可能希望将整个 object 包含在导出中。

您总共有四个选项。 对于顶层,您可以使用以元数据 object 中的名称作为键的 object,或者您可以使用数组。 对于值,您可以使用 object,键是元数据对象的名称,值是 object,包含组件和元数据 object,或者您可以使用数组。 这些选项可以混合和匹配。

使用 arrays 作为值要求它们是as const ,以便 TypeScript 可以推断出正确的类型。

// Array + array
export default [
  [Panel, PanelMetadata] as const,
];

// Array + object
export default [
  { component: Panel, metadata: PanelMetadata },
]

// Object + array
export default {
  [PanelMetadata.name]: [Panel, PanelMetadata] as const,
};

// Object + object
export default {
  [PanelMetadata.name]: { component: Panel, metadata: PanelMetadata },
};

插入

您在此处使用的内容取决于您使用的是名称还是元数据 object 以及用于导出组件的方法。

只是一个名字和简单的 object:

lib.ts

// Assuming a default export.
import components from './components';
import { App } from '@vue/runtime-core';

const plugin = {
    // This is the app instance created by `createApp`.
    install(app: App) {
        // Get the `(key, value)` pairs of the export 
        // and register a component for each of them.
        Object.entries(components).forEach(([name, component]) => {
            app.component(name, component);
        });
    },
};

export default plugin;

对于其他导出方法之一:

// Array + array
components.forEach(([component, metadata]) => {
    app.component(metadata.name, component);
});

// Array + object
components.forEach(({ component, metadata }) => {
    app.component(metadata.name, component);
});

// Object + array
Object.values(components).forEach(([component, metadata]) => {
    app.component(metadata.name, component);
});

// Object + object
Object.values(components).forEach(({ component, metadata }) => {
    app.component(metadata.name, component);
});

您可能会在迭代和回调参数中看到模式。

您也可以将Object.entries用于顶级对象,但这不太干净:

// For array values
Object.entries(components).forEach(([name, componentData]) => {
    app.component(name, componentData[1]);

// For object values
Object.entries(components).forEach(([name, componentData]) => {
    app.component(name, componentData.component);
});

文档

来自app.component()的 API 文档:

如果同时传递名称字符串和组件定义,则注册全局组件,或者如果仅传递名称,则检索已注册的组件。

有关详细信息,请参阅组件注册文档

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM