如果我问“vue-class-component 是如何工作的”,很可能这个问题也被标记为宽的。顺便说一下,我检查了它的源代码,但不明白它是如何工作的,所以我需要从简单的事情开始。
这是 Vue 文档 中的简单示例
export default {
props: ['foo'],
created() {
console.log(this.foo)
}
}
: ECMAScript(甚至 OOP),下面的类不等于上面的对象。
export default class Component {
private foo!: string;
protected created(): void {
console.log(this.foo)
}
}
所以,我认为问题陈述是使用装饰器,如下所示
@MagicDecorator
class Component {
@VueProperty({ type: String })
protected foo!: string;
@VueLifecycleHook
protected created(): void {
console.log(this.foo)
}
}
将其转换为第一个列表。这个问题表述正确吗?
请注意,我没有完全按照 vue-class-component 的方式去做的目标 - 欢迎改进。例如,我将向生命周期挂钩、数据和计算属性添加装饰器,这与 vue-class-component 不同。
If I asked "How vue-class-component works", most likely this question has been marked as too wide. By the way, I checked it's source code, but did not understood how it works, so I need to start from something simple.
Here is the simple example from the Vue documentation:
export default {
props: ['foo'],
created() {
console.log(this.foo)
}
}
From the viewpoint of ECMAScript (and even OOP), below class is NOT equivalent to above object.
export default class Component {
private foo!: string;
protected created(): void {
console.log(this.foo)
}
}
So, I suppose the problem statement is using decorators as below
@MagicDecorator
class Component {
@VueProperty({ type: String })
protected foo!: string;
@VueLifecycleHook
protected created(): void {
console.log(this.foo)
}
}
convert it to first listing. Is this problem statement right?
Please not that I don't have target to do exactly as it vue-class-component - impovements are welcome. For example, I'm going to add decorators to lifecycle hooks, data and computed properties unlike vue-class-component.
发布评论
评论(1)
是的,你是正确的。装饰者做了所有的魔术。它与打字稿无直接相关。可以通过仅使用JavaScript和Babel的装饰插件来完成。我认为Vue级组件的源代码已经解释了所有内容,但让我们自己构建最低版本。为了使事情变得简单,我只使用JavaScript。
我们的目标是创建一个可以将类转换为VUE组件对象的装饰器,例如:
它实际上很简单。我们创建一个新对象,然后将类的所有方法复制到对象。让我们首先创建我们的装饰函数:
选项
将是我们转换后的结果。现在,我们想循环浏览课程,以了解什么属性和哪些方法。请注意,
object.keys(componentClass.protype)
无法使用。因为这些属性是不可启用的属性(由object.defineproperty()
),对于
opted>已安装
,创建
,或数据
,我们只是直接复制它。您可以在VUE源代码中找到挂钩方法列表。是的,这很简单,只需将其复制到我们的
options
。现在,对于自定义方法,我们必须将其放入
方法
对象中。实际上,现在它已经在工作,可以处理许多简单的组件!像上面的计数器组件一样,它现在得到了我们的装饰器的完全支持。
但是我们知道VUE已经计算出属性。我们也支持此功能。
计算的属性是通过Geters和Setter的支持。现在有点棘手,因为您会注意到我们可以直接访问它们,
因为当您以这种方式访问它时,您实际上是在调用Getter。幸运的是,我们可以使用
object.getownPropertyDescriptor()
获取实际的Getter和Setter功能。然后,我们要做的就是将其放入计算的
字段中。在Vue-Class组件的源代码中,他们也使用描述符处理
方法
:最后,我们不会支持构造函数。我们只将其添加到循环的第一个并忽略它:
现在,我们有一个完整的示例。在此处查看它:
注释1:我们的最低示例不使用简单的类属性来支持数据:
如果我们想要为了支持类属性,我们必须将其转换为我们自己的反应性属性。
注2:Babel支持两个版本的装饰师。要与Vue-Class-Component的源代码保持一致,我正在使用旧版。因此,您必须在
@babel/plugin-proposal-decorators
插件中指定{遗产:true}
选项。Yes you are correct. The decorator did all the magics. It's not directly related to TypeScript. It can be done by using only JavaScript and the decorator plugin of babel. I think the source code of vue-class-components has explained everything, but let's build a minimum version by ourself. To keep things simple, I'm using JavaScript only.
Our goal is to create a decorator that can convert a class to a vue component object, like:
It's actually quite straightforward. We create a new object, and copy all the methods of the class to the object. Let's create our decorator function first:
The
options
will be our converted result. Now, we want to loop through the class, to find out what properties and what methods it has.Please note that
Object.keys(ComponentClass.prototype)
won't work. Because those are non-enumerable properties (defined byObject.defineProperty()
)Now, for built-in hook methods like
mounted
,created
, ordata
, we just copy it directly. You can find the list of hook methods in the Vue source code.Yes it's that simple, just copy it to our
options
.Now, for custom methods, we have to put it in a
methods
object.Actually now it's already working and can handle many simple components! Like the above counter component, it's fully supported by our decorator now.
But we know that Vue has computed properties. Let's support this feature as well.
Computed properties are support via getters and setters. Now it's a little bit tricky, because you will notice that we can access them directly by
Because when you access it this way, your are actually calling the getter. Luckily, we can use
Object.getOwnPropertyDescriptor()
to get the actual getter and setter functions. And then all we need to do is put it into thecomputed
field.In the source code of vue-class-components, they handle
methods
by using the descriptor as well:Finally, we are not going to support the constructor. We just add this to the very first of the loop and ignore it:
Now, we have a full working example. See it in action here: https://codesandbox.io/s/stackoverflow-vue-class-component-uhh2jg?file=/src/MagicDecorator.js
Note 1: our minimum example doesn't support data by using a simple class property:
If we want to support the class property, we have to convert it to a reactive property by ourself.
Note 2: Babel supports two versions of decorators. To align with the source code of vue-class-component, I'm using the legacy one. So you have to specify
{legacy: true}
options in the@babel/plugin-proposal-decorators
plugin.