【发布时间】:2018-08-27 11:45:50
【问题描述】:
在PHP 中,当我们包含来自另一个文件的代码时,我们包含它,仅此而已,现在我们可以在执行包含的文件中使用代码。但是在Vue.js中,在导入一个组件后我们还必须导出它。
为什么?我们为什么不简单地导入它?
【问题讨论】:
-
你没有。您能否提供一个小代码示例来说明您的意思?
在PHP 中,当我们包含来自另一个文件的代码时,我们包含它,仅此而已,现在我们可以在执行包含的文件中使用代码。但是在Vue.js中,在导入一个组件后我们还必须导出它。
为什么?我们为什么不简单地导入它?
【问题讨论】:
在
Vue.js中,导入组件后我们还必须导出它。
我想您可能会参考User.vue 中的以下几行,并想知道为什么将UserDetail 和UserEdit 导入到文件中,然后在脚本导出的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.
当 Vue 尝试在 App.vue 的模板中渲染 <user /> 时,Vue 不知道如何解析内部的 <app-user-detail> 和 <app-user-edit>,因为它们的组件注册丢失。这些错误可以通过User.vue 中的本地组件注册来解决(即上面显示的components 属性)。
或者,可以使用global component registration 的UserDetail 和UserEdit 解决错误,这样可以避免在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(...);
【讨论】:
vue 中的组件可能很棘手。如果您还没有,我强烈建议您阅读 vue.js 网站上有关组件注册如何工作的文档,具体来说,因为 tony19 提到了 global 和 local registration。您在屏幕截图中显示的代码示例实际上做了几件事。一方面,它使组件在本地可用,并且只能在本地(如在那个 .vue 文件中)使用。此外,它还使其可作为您在 components 对象中提供的 key 提供给模板,在本例中为 app-user-detail 和 app-user-edit,而不是 user-detail 和 user-edit。
重要的是,应该提到import 实际上并不需要此组件注册才能运行。您可以在一个文件中定义多个组件。 components 键提供了一种方法来识别该组件正在使用什么。所以import 不是必需的,所以vue 确实需要components 键来了解您作为组件使用的内容,以及其他代码。
最后,正如其他一些答案所暗示的那样,components 键实际上并不是导出。 vue 组件的默认签名需要export,但这不是导出components 键下列出的组件。它正在做的是让vue 以自上而下的方式构建。根据您的应用程序设置的其余部分,您可能使用或不使用单个文件组件。无论哪种方式,vue 都将从顶级 vue instance 开始,然后向下遍历组件,除了全局注册,没有顶级组件知道在它下面使用了哪些组件。
这意味着vue 要正确渲染事物,每个组件都必须包含对其使用的额外组件的引用。此引用作为更高级别组件的一部分(在您的情况下为User.vue)导出,但不是组件本身(UserDetail.vue)。
所以看起来vue 需要在导入后进行第二次导出,但实际上它正在做其他事情以允许根 vue 实例呈现您的组件。
顺便说一句,关于这个主题的 vue 文档确实非常好,如果你还没有,请查看我上面链接的部分。关于模块导入/导出系统的附加部分似乎与您的要求高度相关,您可以在此处找到:Module-systems。
【讨论】:
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 元素中呈现 <App/>,并告诉它应该在 ./App.vue 中找到这个元素。
但如果 Vue 编译器“更智能”,我们就不能省略 export 吗?是的,没有。是的,因为编译器可以将很多东西转换为有效的 javascript,而不是因为它没有任何意义,并且严重限制了您可以对组件执行的操作,同时也使编译器更容易出错、更难理解并且总体上更没用。
【讨论】:
为了使App.vue 能够使用User 组件,您需要导出User.vue 文件的default object。
在export default { 中,您实际上并没有导出新导入的组件。您只是在导出一个完全正常的JavaScript Object。这个对象恰好有一个对另一个对象的引用。
当您import 一个对象(或函数或数组或...)时,它不会实际上将该文件的内容加载到您的组件中,如 PHP。它只是确保您的编译器(可能是 webpack)知道如何构建程序。它基本上创建了一个引用,因此 webpack 知道在哪里寻找功能。
【讨论】:
这里的import和export在概念上是不同且不相关的东西,都必须使用。
导入 Vue 组件与 JavaScript 中的任何其他导入相同:
// foo.mjs
export function hello() {
return "hello world!";
}
// bar.mjs
import { hello } from './foo.mjs';
console.log(hello());
现在运行node bar.mjs,你会感觉到导入是如何工作的——你想使用在其他地方定义/实现的东西,然后你必须导入它,不管它是否是一个 Vue 组件.
关于导出,您不是在导出导入的组件。您唯一要导出的是当前组件。但是,当前组件可能在其<template> 中使用了一些其他子组件,因此必须通过在导出对象的components 字段中指定这些子组件来注册这些子组件。
【讨论】: