如何为Vue自动注册组件(用Vite)?

468 阅读6分钟

组件是Vue的核心功能。

事实上,你经常会发现自己编写了数百个组件,这意味着在一个大型项目中,导入和注册组件会变得很单调。😤

这句话对于通用组件来说尤其正确,但幸运的是,有一个自动注册基础组件的解决方法。这可以提高生产力,使你的生活变得更容易,所以我几乎对所有的项目都推荐这样做。

否则,让我们深入了解一下,我们将向你展示如何在Vite中设置自动注册组件

什么时候应该(和不应该)自动注册组件

我知道我刚刚给你讲了为什么要自动注册组件,但是如果你不小心的话,你会陷入一些陷阱。

请牢记这两个重要的细节。

  • 不是所有的组件都需要被导入和注册。你应该总是懒惰地加载组件以提高你的应用程序的性能。
  • 通过自动注册组件,可能不清楚一个组件是在哪里定义的。它是由第三方软件包还是由你的应用程序定义的?

由于这些原因,自动注册组件对那些通用的、在你的应用程序中多次使用的组件效果最好

这听起来像是你在自己的应用程序中需要的东西吗?

那么,让我们试一试吧!

步骤#1️ 准备项目

你可以将这段代码应用于任何项目。

如果你已经有了一个项目,那么请跳到下一节,但如果你想从一个新的项目开始并跟着做,你可以在Stackblitz上这样做。

另外,你也可以运行以下命令。

注意:这个解决方案只适用于Vite。Webpack项目不能使用这个代码

步骤#2️ 安装Lodash

虽然不是必须的,但Lodash可以帮助我们格式化组件的名称,以确保一致性,所以使用它很有帮助。

你可以用以下命令来安装Lodash。

💡 最高提示

Vue有一个风格指南,其中有关于组件应该如何命名的建议,所以请随意使用Lodash来帮助你遵守这些准则。

步骤#3️ 创建基础组件

在这个例子中,让我们在src/components/中创建一个专门用于基础组件的目录,名为base

为什么?

因为如果组件不是散落在你的项目中,导入它们会更容易。

接下来,让我们添加两个基础组件,叫做Button.vueHeader.vue。在这两个组件中,我们将添加一些模板代码。

Button.vue:

<template>
  <button>
    Hello world!
  </button>
</template>

Header.vue

<template>
  <h1>What's up!</h1>
</template>

最后,让我们从App.vue组件中包含这些组件:

<template>
  <BaseButton />
  <BaseHeading />
</template>

在上面的例子中,我们在组件前加上Base ,以帮助开发者识别这些组件是通用组件。

步骤#4️ 创建一个Vue插件

Vue的功能可以通过插件来扩展,所以让我们创建自己的插件。

为什么?

通过使用一个插件,我们被赋予了对当前Vue实例的访问权,而且我们将能够在不同的项目中导出我们的插件。

src目录中,创建一个名为globals.js的文件,代码如下。

import _ from 'lodash';

export default {
  install(app) {

  }
};

一个插件只是一个对象,它有一个名为install() 的方法。

我们可以注册组件、指令,或者对这个实例执行其他操作。

除了定义插件之外,我们还要导入Lodash,因为我们在以后的工作中会需要它的功能。

步骤#5️ 使用Globs来查找文件

在编程领域,有一个特殊的概念,叫做glob。(不,不是指X-men)。

Blog post image

Glob "是一种在文件系统中使用模式来定位文件的功能,不同的编程语言和工具对这一功能的实现方式不同。

对于Vite,我们有两个使用glob的函数,叫做import.meta.glob()import.meta.globEager()

import.meta.glob() 函数将懒惰地加载文件,这不是我们想要的,因为我们感兴趣的是立即导入和注册组件。

在这种情况下,我们可以使用import.meta.globEager() 函数来代替,因为它不会懒惰地加载组件。

install() 方法中,我们要使用这个函数,如下所示。

const componentFiles = import.meta.globEager(
  './components/base/*.vue'
);

这个函数不需要被导入,因为它是通过Vite自动提供的。

在幕后,Vite使用了一个名为fast-glob的包。请查看链接,了解支持的模式语法的信息。

传入这个函数的值是一个模式,Vite将使用这个模式开始导入文件。我们提供的是一个相对路径,即组件/基地目录。

在路径的后半部分,* 字符充当通配符。任何以vue扩展名结尾的文件都将被导入。

导入的文件将作为一个对象返回,并存储在一个名为componentFiles 的变量中。

步骤#6️ 注册组件

下一步是开始注册组件。

然而,由于我们不知道会有多少组件被返回,最好是循环浏览组件列表。

我们有两个选项可以使用。

componentFiles 变量将存储一个对象,除非我们使用for of 循环,否则它是不能循环的。

另外,我们可以通过使用Object.entries() 方法将我们的对象转换成一个数组,像这样。

Object.entries(componentFiles).forEach(([path, m]) => {

})

Object.entries() 方法将通过存储每个键值对将一个对象转换成一个数组,其中第一项是键,第二项是值。

转换之后,我们可以开始使用数组方法来循环浏览导入的组件。

为了提高可读性,我建议对数组进行解构。这样,数组中的第一项将存储文件的路径,而数组中的第二项则存储组件对象。

在这个循环中,我们可以开始准备组件的名称。

const componentName = _.upperFirst(
  _.camelCase(path.split('/').pop().replace(/\.\w+$/, ''))
);

注意

path 变量将包含文件的完整路径,这并不适合作为一个组件名称。

为了准备Vue注册的名称,我们要使用_.upperFirst()_.camelCase() 函数。upperFirst() 函数将对名称中的第一个字符进行大写。camelCase() 函数将把名字中的每个字大写。

在使用这些函数之前,我们要从路径中剥离文件名,并删除.vue 的扩展名。这将使我们只剩下组件的名称。

例如,如果我们有以下路径/some/path/Example.vue ,结果将变成Example

在所有的事情都完成后,我们可以用component() 函数来注册该组件。在下面的例子中,我们的组件前缀为Base ,以防止命名冲突,由于组件是在默认的命名空间下导出的,所以可以在m.default 属性下访问组件数据。

app.component(
  `Base${componentName}`, m.default
);

总的来说,这个解决方案看起来是这样的。

import _ from 'lodash';

export default {
  install(app) {
    const componentFiles = import.meta.globEager(
      './components/base/*.vue'
    );

    Object.entries(componentFiles).forEach(([path, m]) => {
      const componentName = _.upperFirst(
        _.camelCase(path.split('/').pop().replace(/\.\w+$/, ''))
      );

      app.component(
        `Base${componentName}`, m.default
      );
    })
  },
};

步骤#7️ 使用Vue插件

现在我们可以开始使用我们的插件了,在应用程序被创建后但在其被挂载前,导入文件并链入use() 函数。

import { createApp } from 'vue'
import App from './App.vue'
import GlobalComponents from './globals'

createApp(App)
  .use(GlobalComponents)
  .mount('#app')

如果我们在注册我们的插件之前加载应用程序,我们的组件可能在加载阶段无法使用。

重要的是,你应该总是在挂载前注册插件。

你还在等什么呢?去自动注册你的组件吧!

就这样,你有了一个为Vue自动注册组件的7步流程。

你可以简单地跟随并为自己设置,但在这之前,我只想指出最后一件事。

一个替代的解决方案...

有一个Vite插件可以自动注册/自动导入组件,叫做Unplugin Vue Component,我们也可以使用。

但等等,这是否意味着我们所有的努力都白费了!?

不一定,因为我们上面刚用的方法还有额外的好处。

比如什么?

嗯,我们的解决方案可以扩展到导入指令、类或你能想象到的任何其他类型的文件。同样地,它也不局限于组件。不管怎么说,你现在有了这两种解决方案,可以自由支配了😄