【问题标题】:In Vue.js why do we have to export components after importing them?在 Vue.js 中,为什么我们必须在导入组件后导出它们?
【发布时间】:2018-08-27 11:45:50
【问题描述】:

PHP 中,当我们包含来自另一个文件的代码时,我们包含它,仅此而已,现在我们可以在执行包含的文件中使用代码。但是在Vue.js中,在导入一个组件后我们还必须导出它。

为什么?我们为什么不简单地导入它?

【问题讨论】:

标签: vue.js vuejs2


【解决方案1】:

Vue.js 中,导入组件后我们还必须导出它。

我想您可能会参考User.vue 中的以下几行,并想知道为什么将UserDetailUserEdit 导入到文件中,然后在脚本导出的components 属性中导出:

import UserDetail from './UserDetail.vue';
import UserEdit from './UserEdit.vue';

export default {
  components: {
    appUserDetail: UserDetail,
    appUserEdit: UserEdit
  }
}

vue-loader 期望.vue 文件的脚本导出包含组件的定义,该定义实际上包括组装组件模板的配方。如果模板包含其他 Vue 组件,则需要提供其他组件的定义,否则称为component registration。正如@Sumurai8 所指出的,.vue 文件的导入本身并没有注册相应的单文件组件;相反,这些组件必须在导入器的components 属性中显式注册。

例如,如果App.vue的模板包含<user />User.vue被定义为:

<template>
  <div class="user">
    <app-user-edit></app-user-edit>
    <app-user-detail></app-user-detail>
  </div>
</template>

<script>
export default {
  name: 'user'
}
</script>

...User 组件将呈现为空白,您将看到以下控制台错误:

[Vue warn]: Unknown custom element: <app-user-edit> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
[Vue warn]: Unknown custom element: <app-user-detail> - did you register the component correctly? For recursive components, make sure to provide the "name" option.

demo 1

当 Vue 尝试在 App.vue 的模板中渲染 &lt;user /&gt; 时,Vue 不知道如何解析内部的 &lt;app-user-detail&gt;&lt;app-user-edit&gt;,因为它们的组件注册丢失。这些错误可以通过User.vue 中的本地组件注册来解决(即上面显示的components 属性)。

或者,可以使用global component registrationUserDetailUserEdit 解决错误,这样可以避免在User.vue 中进行本地注册。请注意,必须在创建 Vue 实例之前完成全局注册。示例:

// main.js
import Vue from 'vue';
import UserDetail from '@/components/UserDetail.vue';
import UserEdit from '@/components/UserEdit.vue';

Vue.component('app-user-detail', UserDetail);
Vue.component('app-user-edit', UserEdit);

new Vue(...);

demo 2

【讨论】:

    【解决方案2】:

    vue 中的组件可能很棘手。如果您还没有,我强烈建议您阅读 vue.js 网站上有关组件注册如何工作的文档,具体来说,因为 tony19 提到了 global 和 local registration。您在屏幕截图中显示的代码示例实际上做了几件事。一方面,它使组件在本地可用,并且只能在本地(如在那个 .vue 文件中)使用。此外,它还使其可作为您在 components 对象中提供的 key 提供给模板,在本例中为 app-user-detailapp-user-edit,而不是 user-detailuser-edit

    重要的是,应该提到import 实际上并不需要此组件注册才能运行。您可以在一个文件中定义多个组件。 components 键提供了一种方法来识别该组件正在使用什么。所以import 不是必需的,所以vue 确实需要components 键来了解您作为组件使用的内容,以及其他代码。

    最后,正如其他一些答案所暗示的那样,components 键实际上并不是导出。 vue 组件的默认签名需要export,但这不是导出components 键下列出的组件。它正在做的是让vue 以自上而下的方式构建。根据您的应用程序设置的其余部分,您可能使用或不使用单个文件组件。无论哪种方式,vue 都将从顶级 vue instance 开始,然后向下遍历组件,除了全局注册,没有顶级组件知道在它下面使用了哪些组件

    这意味着vue 要正确渲染事物,每个组件都必须包含对其使用的额外组件的引用。此引用作为更高级别组件的一部分(在您的情况下为User.vue)导出,但不是组件本身(UserDetail.vue)。

    所以看起来vue 需要在导入后进行第二次导出,但实际上它正在做其他事情以允许根 vue 实例呈现您的组件。

    顺便说一句,关于这个主题的 vue 文档确实非常好,如果你还没有,请查看我上面链接的部分。关于模块导入/导出系统的附加部分似乎与您的要求高度相关,您可以在此处找到:Module-systems

    【讨论】:

      【解决方案3】:

      import 将代码导入当前文件,但它自己不做任何事情。想象一下下面的非 vue 代码:

      // File helpers.js
      export function tickle(target) {
        console.log(`You tickle ${target}`)
      }
      
      // File main.js
      import { tickle } from 'helpers'
      

      您已导入代码,但它没有执行任何操作。要真正给东西挠痒痒,你需要调用这个函数。

      tickle('polar bear');
      

      在 Vue 中也是如此。您定义了一个组件(或实际上只是一个对象),但该组件自己不做任何事情。您导出此组件,以便可以将其导入 Vue 库可以使用此对象执行某些操作的其他地方。

      在 Vue 组件中,您可以导出当前组件,并导入您在模板中使用的组件。您通常会执行以下操作:

      <template>
        <div class="my-component">
          <custom-button color="red" value="Don't click me" @click="tickle" />
        </div>
      </template>
      
      <script>
      import CustomButton from './CustomButton';
      
      export default {
        name: 'my-component',
        components: {
          CustomButton
        }
      }
      </script>
      

      您的组件提到了一个名为“自定义按钮”的组件。这不是一个普通的 html 元素。它不知道如何正常处理它。那么我们该怎么办?我们导入它,然后将其放入components。这会将名称 CustomButton 映射到您导入的组件。它现在知道如何渲染组件了。

      “魔法”发生在您使用 Vue 挂载根组件时,通常在您的 main.js 中。

      import Vue from "vue";
      import App from "./App";
      
      Vue.config.productionTip = false;
      
      /* eslint-disable no-new */
      new Vue({
        el: "#app",
        components: { App },
        template: "<App/>"
      });
      

      这是做什么的?你告诉 Vue 在由 #app 标识的 html 元素中呈现 &lt;App/&gt;,并告诉它应该在 ./App.vue 中找到这个元素。


      但如果 Vue 编译器“更智能”,我们​​就不能省略 export 吗?是的,没有。是的,因为编译器可以将很多东西转换为有效的 javascript,而不是因为它没有任何意义,并且严重限制了您可以对组件执行的操作,同时也使编译器更容易出错、更难理解并且总体上更没用。

      【讨论】:

        【解决方案4】:

        为了使App.vue 能够使用User 组件,您需要导出User.vue 文件的default object

        export default { 中,您实际上并没有导出新导入的组件。您只是在导出一个完全正常的JavaScript Object。这个对象恰好有一个对另一个对象的引用

        当您import 一个对象(或函数或数组或...)时,它不会实际上将该文件的内容加载到您的组件中,如 PHP。它只是确保您的编译器(可能是 webpack)知道如何构建程序。它基本上创建了一个引用,因此 webpack 知道在哪里寻找功能。

        【讨论】:

          【解决方案5】:

          TL;DR

          这里的importexport在概念上是不同且不相关的东西,都必须使用。


          导入 Vue 组件与 JavaScript 中的任何其他导入相同:

          // foo.mjs
          export function hello() {
                  return "hello world!";
          }
          
          
          // bar.mjs
          import { hello } from './foo.mjs';
          
          console.log(hello());
          

          现在运行node bar.mjs,你会感觉到导入是如何工作的——你想使用在其他地方定义/实现的东西,然后你必须导入它,不管它是否是一个 Vue 组件.

          关于导出,您不是在导出导入的组件。您唯一要导出的是当前组件。但是,当前组件可能在其&lt;template&gt; 中使用了一些其他子组件,因此必须通过在导出对象的components 字段中指定这些子组件来注册这些子组件。

          【讨论】:

            猜你喜欢
            • 2014-09-05
            • 2013-11-09
            • 2020-07-17
            • 2018-10-11
            • 1970-01-01
            • 2015-06-08
            • 2012-04-10
            • 1970-01-01
            相关资源
            最近更新 更多