【发布时间】:2017-04-04 18:58:48
【问题描述】:
这很简单,但我没有从文档中得到我需要的答案。我正在学习 Vue.js,但我不太明白 Vue.extend 适合哪里。我得到了 Vue.component,但我看不到 Vue.extend 做了哪些 Vue.component 没有.它只是 1.0 的遗留功能吗?如果没有,它在 Vue 2.0 中有什么用处?
【问题讨论】:
标签: vue.js
这很简单,但我没有从文档中得到我需要的答案。我正在学习 Vue.js,但我不太明白 Vue.extend 适合哪里。我得到了 Vue.component,但我看不到 Vue.extend 做了哪些 Vue.component 没有.它只是 1.0 的遗留功能吗?如果没有,它在 Vue 2.0 中有什么用处?
【问题讨论】:
标签: vue.js
他们在之前的 Vuejs.org 网站上的指南有一个文档。
从http://optimizely.github.io/vuejs.org/guide/composition.html 复制而来,该http://optimizely.github.io/vuejs.org/guide/composition.html 是从 Vuejs 0.10.6 版本的 vuejs/Vuejs.org 派生出来的。
了解
Vue.extend()之间的区别很重要 和Vue.component()。由于Vue本身就是一个构造函数,Vue.extend()是一个类继承方法。它的任务是 创建Vue的子类并返回构造函数。 另一方面,Vue.component()是一个资产注册 方法类似于Vue.directive()和Vue.filter()。它的任务是 将给定的构造函数与字符串 ID 相关联,以便 Vue.js 可以选择 它在模板中。当直接将选项传递给Vue.component(),它在后台调用Vue.extend()。Vue.js 支持两种不同的 API 范例:基于类, 命令式、Backbone 风格的 API,以及基于标记的、声明式的 Web 组件样式 API。如果您感到困惑,请考虑如何做 使用
new Image()或<img>标签创建图像元素。 每个都有自己的用途,Vue.js 试图同时提供 最大的灵活性。
【讨论】:
我认为混淆是因为扩展和组件紧密相连。要创建组件 Vue 调用内部扩展:
// register an options object (automatically call Vue.extend)
Vue.component('my-component', { /* ... */ })
因此可以使用extend来挂载Vue基础构造函数的子类(组件构造函数):https://vuejs.org/v2/api/#Vue-extend
但是,您不太可能遇到或需要走这条路。相反,您将使用组件来获取命名的子类,您可以在应用程序中轻松引用这些子类。
因此,Extend 并不是真正的“遗留”功能,它是 Vue 组件的核心,但组件提供的添加糖使它们成为您工作的默认方式。
【讨论】:
除了提供的答案之外,如果您使用的是 TypeScript,还有一个实际用例可以直接调用 Vue.extend()。
在大多数情况下,建议在需要时从其他文件导入组件定义,而不是使用Vue.component() 全局注册它们。它使大型项目中的事物井井有条,并且更容易跟踪问题。
使用正确的库,TypeScript 可以查看您的组件定义并确定组件在初始化时的类型,这意味着它可以检查您定义的函数是否有意义(即,如果您引用this.foo 实际上有一个名为foo 的道具、数据字段、计算值或方法。如果您使用Vue.component(),它将能够做到这一点,但如果您使用其他使组件可用的典型方法,即导出对象文字,则不能。
但是,另一种选择是导出包装在 Vue.extend() 中的组件定义。然后 TypeScript 将能够将其识别为 Vue 组件并相应地运行其类型检查,但您不必放弃导出组件而不是全局注册它们的最佳实践模式。
【讨论】:
this.$refs 时,我为此苦苦挣扎了好几个小时,但我不知道为什么。用Vue.extend({ ..... }) 包裹我的普通对象解决了这个问题。
Vue.extend 的作用帮助我理解了为什么它解决了我在尝试访问 $vuetify 或 $store 时的所有类型错误的原因或 $route 在 nuxt+ts+vuetify 项目中。我能够用Vue.extend 解决它,但在文档中没有看到明确解释为什么这是要走的路。那谢谢啦。也许这将在未来帮助更多的人
Vue v2 的文档在 Vue.extends 上有点稀疏,但简而言之:
您使用Vue.extend 创建组件定义(在旧文档中称为“组件构造函数”)和Vue.component 到register 它可以在模板中使用它来实际创建组件实例。
<div id="example">
<my-component></my-component>
</div>
// define
var MyComponent = Vue.extend({
template: '<div>A custom component!</div>'
})
// register
Vue.component('my-component', MyComponent)
// create a root instance
new Vue({
el: '#example'
})
但是,在 Vue API 中可以传递由Vue.extend 创建的“组件构造函数”的任何地方,您都可以传递普通对象,它将调用Vue.extend for you。
所以前面的例子可以写成
// define
var MyComponent = {
template: '<div>A custom component!</div>'
}
// register
Vue.component('my-component', MyComponent)
// create a root instance
new Vue({
el: '#example'
})
人们现在更喜欢将组件定义为普通的 JS 对象(在 Vue 世界中称为 options 对象)。
您可以看到,在 Vue v2 的当前文档中,您很少看到 Vue.extends 提及,而在 v1 的文档中,它在描述 Vue Instance 的第一章中明确解释(与 v2 比较)并且非常在Components 章节中有很好的解释。明确指出直接传递选项对象只是sugar。
我的猜测是,为了保持简单和易于学习,新文档在任何地方都使用普通对象。为什么在 99% 的时间不需要理解时还要解释诸如“Vue 构造函数”、“组件构造函数”以及什么是 Vue.extend 之类的附加概念?您可以使用纯 JS 选项对象和 register 定义您的应用程序的所有组件,而无需使用 Vue.extends。唯一必须使用 vue 构造函数的地方是使用 new Vue({...}) 创建 root Vue 实例。这使用基本Vue 构造函数。您不需要知道 Vue 构造函数可以扩展以创建具有预定义选项的可重用组件构造函数,因为 尽管您可以命令式地创建扩展实例,但在大多数情况下,您将注册一个组件构造函数作为自定义元素,并以声明方式将它们组合在模板中。(source)
因此文档作者决定您不需要了解Vue.extends。但是有没有值得使用 Vue.extend 而不是普通的 options 对象的用例?
是的。
如果您想使用 Typescript(并且不喜欢 class-style 组件),那么要进行正确的类型推断,您 should 使用 Vue.extend 而不是普通对象。它使用ThisType<T> feature 来获得this 对象的正确推断。
您不仅可以在基础Vue 构造函数上使用.extend,还可以在自定义组件上使用.extend。这不如mixins 灵活,因为您可以在组件中使用许多mixin,而.extend 方法仅适用于一个组件。但是,它更适用于 Typescript,其中 mixins 似乎是 not play well。使用.extend,Typescript 支持在许多情况下可能“足够好”。您可以从继承的组件中访问字段,但如果您的组件与“基础”组件有一些名称冲突,那么它就不能正常工作(例如,我得到一个类型为 never 的道具名称冲突)。
<div id="appBar">
{{fooMessage}} || {{barMessage}} || {{ additionalData}}
<button v-on:click="changeAllMessages">Change</button>
</div>
var FooComponent = Vue.extend({
data: () => ({
fooMessage: 'Foo message'
}),
methods: {
changeFooMessage() {
this.fooMessage = "Foo message changed";
}
}
})
var BarComponent = FooComponent.extend({
data: () => ({
barMessage: "Bar message",
}),
methods: {
changeAllMessages() {
this.barMessage = "Bar message changes";
this.changeFooMessage();
}
}
});
new BarComponent({ el: "#appBar", data: { additionalData: "additional data passed" } });
这里我还展示了您可以使用自定义组件来创建 根 Vue 实例 (new BarComponent({...}))。就像您可以使用 new Vue({...}) 一样。也许它没那么有用,但它表明BarComponent 和FooComponent 只是扩展 基本Vue 构造函数,您可以像使用Vue 一样使用它。
【讨论】:
理解 Vue.extend 的一个简单方法是创建一个扩展 Vue 类的对象。
通常,要创建一个新的 Vue 实例,
var vm = new Vue( {/* ...*/})
Vue.extend 也创建了一个 Vue ie 的实例
var page = Vue.extend ({ /* ... */});
page 和上面的 vm 一样是 Vue 的一个实例。
要挂载页面,你必须把它挂载到一个div上,
new page().$mount('#page-div')
#page-div 是您页面中 div 的 Id
另外,对于具有面向对象编程知识的程序员来说
var ext = Vue.extend({/ *...* /})
那么我们可以将 ext 解释为
class ext extends Vue{
}
请注意,当您创建一个组件时,即Vue.component('my-component', { /* ... */ }),它实际上会执行以下操作:Vue.component('my-component', Vue.extend({ /* ... */})),因此 Vue.component 会在后台调用 Vue.extend。
如果您仍然感到困惑,请将Vue.extend 视为创建组件的实用函数
【讨论】: