前言
在一些 Vue 2 + TypeScript 项目中,你可能会看到这样的代码:
javascript
import Vue from 'vue';
import Component from 'vue-class-component';
@Component
export default class UserList extends Vue {
count = 0;
get doubleCount() {
return this.count * 2;
}
add() {
this.count++;
}
mounted() {
console.log('组件挂载完成');
}
}
如果你之前习惯的是 Vue 的 Options API,可能会疑惑:
export default class Xxx extends Vue是什么写法?count = 0为什么可以当作 data?get doubleCount()为什么相当于 computed?add()为什么不用写在 methods 里面?
这类写法通常被称为 class-style Vue,也就是"类风格 Vue 组件"。
本文将从概念、语法对比、实际示例和使用建议几个方面介绍 class-style Vue。
一、什么是 class-style Vue?
class-style Vue 是一种使用 JavaScript / TypeScript 的 class 语法来编写 Vue 组件的方式。
传统 Vue 组件一般是这样写的:
javascript
export default {
data() {
return {
count: 0,
};
},
computed: {
doubleCount() {
return this.count * 2;
},
},
methods: {
add() {
this.count++;
},
},
};
而 class-style Vue 可以写成:
javascript
import Vue from 'vue';
import Component from 'vue-class-component';
@Component
export default class Counter extends Vue {
count = 0;
get doubleCount() {
return this.count * 2;
}
add() {
this.count++;
}
}
可以看到,class-style Vue 把组件写成了一个类:
javascript
export default class Counter extends Vue {
// 组件内容
}
类里面的属性、getter、方法,会被转换成 Vue 组件对应的 data、computed、methods 等配置。
二、为什么会有 class-style Vue?
在 Vue 2 时代,如果项目大量使用 TypeScript,Options API 的类型推导体验并不是特别好。
而使用 class 写法时:count 是类的成员属性,TypeScript 对它的识别更加直观。
因此,在 Vue 2 + TypeScript 项目中,class-style Vue 曾经是比较常见的一种写法。
三、class-style Vue 需要哪些库?
在 Vue 2 项目中,class-style Vue 通常会用到以下库:
bash
vue-class-component
vue-property-decorator
其中:
1. vue-class-component
它是 class-style Vue 的核心库,用来让 Vue 识别 class 组件。
常见用法:
javascript
import Vue from 'vue';
import Component from 'vue-class-component';
@Component
export default class Demo extends Vue {
message = 'Hello Vue';
}
2. vue-property-decorator
它基于 vue-class-component,提供了更方便的装饰器,例如:
@Prop@Watch@Emit@Provide@Inject
示例:
javascript
import { Component, Vue, Prop, Watch } from 'vue-property-decorator';
@Component
export default class Demo extends Vue {
@Prop(String)
title!: string;
@Watch('title')
onTitleChange(newVal: string) {
console.log(newVal);
}
}
四、Options API 和 class-style Vue 对比
下面我们通过常见功能对比一下两种写法。
1. data 的写法
Options API
javascript
export default {
data() {
return {
count: 0,
name: '张三',
};
},
};
class-style Vue
javascript
@Component
export default class Demo extends Vue {
count = 0;
name = '张三';
}
在 class-style Vue 中,类的实例属性会被作为组件的响应式数据。
2. computed 的写法
Options API
javascript
export default {
data() {
return {
count: 1,
};
},
computed: {
doubleCount() {
return this.count * 2;
},
},
};
class-style Vue
javascript
@Component
export default class Demo extends Vue {
count = 1;
get doubleCount() {
return this.count * 2;
}
}
在 class-style Vue 中,get 访问器会被识别为计算属性。
使用时也一样,不需要加括号:
javascript
<div>{{ doubleCount }}</div>
3. methods 的写法
Options API
javascript
export default {
methods: {
add() {
this.count++;
},
},
};
class-style Vue
javascript
@Component
export default class Demo extends Vue {
count = 0;
add() {
this.count++;
}
}
在 class-style Vue 中,类中的普通方法会被当作 Vue 的 methods。
4. props 的写法
Options API
javascript
export default {
props: {
title: {
type: String,
default: '',
},
},
};
class-style Vue
javascript
import { Component, Vue, Prop } from 'vue-property-decorator';
@Component
export default class Demo extends Vue {
@Prop({
type: String,
default: '',
})
title!: string;
}
! 是 TypeScript 的非空断言写法。
表示告诉 TypeScript:
这个属性会由 Vue 在运行时注入,不需要我在构造阶段初始化。
5. watch 的写法
Options API
javascript
export default {
data() {
return {
keyword: '',
};
},
watch: {
keyword(newVal, oldVal) {
console.log('keyword changed:', newVal, oldVal);
},
},
};
class-style Vue
javascript
import { Component, Vue, Watch } from 'vue-property-decorator';
@Component
export default class Demo extends Vue {
keyword = '';
@Watch('keyword')
onKeywordChange(newVal: string, oldVal: string) {
console.log('keyword changed:', newVal, oldVal);
}
}
如果需要深度监听或者立即执行,可以这样写:
javascript
@Watch('userInfo', {
deep: true,
immediate: true,
})
onUserInfoChange(newVal: any) {
console.log(newVal);
}
6. 生命周期的写法
Options API
javascript
export default {
created() {
console.log('created');
},
mounted() {
console.log('mounted');
},
beforeDestroy() {
console.log('beforeDestroy');
},
};
class-style Vue
javascript
@Component
export default class Demo extends Vue {
created() {
console.log('created');
}
mounted() {
console.log('mounted');
}
beforeDestroy() {
console.log('beforeDestroy');
}
}
五、class-style Vue 的优点
1. 更接近面向对象写法
对于熟悉 Java、C#、TypeScript class 的开发者来说,这种写法更直观:
javascript
export default class UserPage extends Vue {
userList = [];
get total() {
return this.userList.length;
}
loadUserList() {
// 请求用户列表
}
}
状态和方法都作为类成员存在。
2. TypeScript 体验较好
在 Vue 2 时代,class-style 写法对 TypeScript 支持相对友好。
例如:
javascript
count = 0;
add() {
this.count++;
}
TypeScript 可以很自然地知道 count 是一个数字。
3. 代码结构比较集中
class-style Vue 不需要把代码拆到:
- data
- computed
- methods
- watch
这些不同配置项中,而是直接写在类里。
例如:
javascript
keyword = '';
get filteredList() {
return this.list.filter(item => item.name.includes(this.keyword));
}
search() {
this.loadData();
}
对于一些开发者来说,这样的代码更连贯。
六、class-style Vue 的缺点
1. 学习成本更高
class-style Vue 引入了额外概念:
- class
- decorator
@Component@Prop@Watch- TypeScript 的
! - getter / setter
对于新手来说,不如 Options API 直观。
2. 和 Vue 官方主推方向不完全一致
Vue 3 之后,官方更推荐:
- Options API
- Composition API
<script setup>
尤其是 Composition API 和 <script setup> 已经成为很多新项目的主流选择。
例如 Vue 3 中更常见的写法是:
javascript
<script setup lang="ts">
import { ref, computed } from 'vue';
const count = ref(0);
const doubleCount = computed(() => {
return count.value * 2;
});
function add() {
count.value++;
}
</script>
3. 装饰器语法可能带来兼容性问题
class-style Vue 常常依赖装饰器,例如:
javascript
@Prop(String)
title!: string;
装饰器在不同 TypeScript、Babel、构建工具版本中的配置可能会有差异。
项目迁移或升级时,可能会遇到一些兼容性问题。
4. Vue 3 中不再是主流选择
虽然 Vue 3 仍然可以通过相关库支持 class-style 写法,但实际项目中,更多团队会选择:
javascript
<script setup lang="ts">
因为它更简单,类型推导也更好。
七、class-style Vue 与 Vue 3 Composition API 对比
假设我们要写一个计数器组件。
class-style Vue
javascript
import { Component, Vue } from 'vue-property-decorator';
@Component
export default class Counter extends Vue {
count = 0;
get doubleCount() {
return this.count * 2;
}
add() {
this.count++;
}
}
Vue 3 <script setup>
javascript
<script setup lang="ts">
import { ref, computed } from 'vue';
const count = ref(0);
const doubleCount = computed(() => {
return count.value * 2;
});
function add() {
count.value++;
}
</script>
模板中都可以这样用:
javascript
<template>
<div>
<p>{{ count }}</p>
<p>{{ doubleCount }}</p>
<button @click="add">增加</button>
</div>
</template>
八、总结
class-style Vue 是 Vue 组件的一种类风格写法,主要出现在 Vue 2 + TypeScript 项目中。
它的核心对应关系如下:
| Options API | class-style Vue |
|---|---|
data() |
类属性 |
computed |
get xxx() |
methods |
类方法 |
props |
@Prop |
watch |
@Watch |
| 生命周期 | 类方法,如 mounted() |
简单来说:
class-style Vue 就是用
class Xxx extends Vue的方式写 Vue 组件。类属性相当于 data,get相当于 computed,普通方法相当于 methods。
对于老项目维护来说,理解 class-style Vue 非常重要;但如果是 Vue 3 新项目,更建议优先选择 Composition API 或 <script setup>。