大家好,我是格子,今天写这个文章的目的是为了,以后如果遇到 Vue 2 用到这个技术栈能快速上手,顺便记录一下 Vue 2 的发展史。如果新项目没有特定的要求建议直接选择 Vue 3 或者 React。因为 Vue 2 在 2023 年 12 月 31 日 官方不再维护,最后一个版本是 Vue 2.7.14,发布于 2022 年 12 月,这就意味着不再会有新特性了,而 Vue 3 不管是从设计上还是开发体验上都有着卓越的表现。
下面开始我们今天的主题
vue-property-decorator
是一个基于 TypeScript 的 Vue 类组件开发工具库,目的是通过 装饰器(Decorators) 语法,简化 Vue 2 组件的开发。它的核心依赖是 vue-class-component
(由 Vue 官方维护),并在其基础上扩展了更多装饰器(如 @Prop
, @Watch
, @Emit
等),提供更接近传统面向对象编程的语法,有 Java
基础的同学可能更喜欢这种编写方式。
- 背景:Vue 2 默认使用选项式 API(Options API),但在 TypeScript 项目中,开发者希望用类的方式组织代码以获得更好的类型检查和代码提示。
- 定位:解决 Vue 2 + TypeScript 项目中代码冗余和类型定义的问题。
使用步骤
1.安装依赖: npm install vue-property-decorator vue-class-component
2.配置 TypeScript: 在 tsconfig.json
中启用装饰器语法:
json
{
"compilerOptions": {
"experimentalDecorators": true, // 启用装饰器
"strictPropertyInitialization": false, // 避免必须初始化类属性
"target": "es5", // 适配装饰器语法
"lib": ["es6", "dom"]
}
}
3.简单使用: 组件开发基础结构
typescript
// MyComponent.vue
<template>
<div>
<h1>{{ message }}</h1>
<button @click="increment">Count: {{ count }}</button>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
@Component
export default class MyComponent extends Vue {
// Data 属性(直接声明为类属性)
message: string = 'Hello, Vue!';
count: number = 0;
// 方法(直接定义为类方法)
increment(): void {
this.count++;
}
// 生命周期钩子(同名方法)
mounted(): void {
console.log('Component mounted');
}
}
</script>
1. 适用版本
- Vue 版本 :专为 Vue 2 设计,尤其适合
[email protected]
+[email protected]
项目。 - Vue 3 兼容性 :Vue 3 推荐使用 Composition API 或
<script setup>
语法,但若需在 Vue 3 中使用类组件,需依赖vue-facing-decorator
或vue-class-component@next
(不推荐)。 - TypeScript 版本 :需支持装饰器语法(TypeScript 3.x+,需在
tsconfig.json
中启用experimentalDecorators
)。
2. 核心装饰器列表
vue-property-decorator
提供以下装饰器:
@Component
@Prop
@PropSync
@Model
@Watch
@Emit
@Inject
@Provide
@Ref
@Mixins
3. 每个装饰器的详细说明与对比
3.1 @Component
- 用途 :定义 Vue 组件,替代
export default {}
。 - 对比:
typescript
// Options API
export default {
name: 'MyComponent',
components: { ChildComponent }
}
// vue-property-decorator
import { Component, Vue } from 'vue-property-decorator';
import ChildComponent from './ChildComponent.vue';
@Component({
components: { ChildComponent }
})
export default class MyComponent extends Vue {}
3.2 @Prop
- 用途:声明组件的 props,支持类型定义和默认值。
- 对比:
typescript
// Options API
props: {
title: { type: String, required: true },
count: { type: Number, default: 0 }
}
// vue-property-decorator
import { Prop } from 'vue-property-decorator';
export default class MyComponent extends Vue {
@Prop({ type: String, required: true }) title!: string;
@Prop({ type: Number, default: 0 }) count!: number;
}
3.3 @PropSync
- 用途 :为需要同步的 prop 生成一个计算属性(用于
v-model
双向绑定)。 - 对比:
typescript
// Options API
props: ['title'],
computed: {
syncedTitle: {
get() { return this.title; },
set(value) { this.$emit('update:title', value); }
}
}
// vue-property-decorator
import { PropSync } from 'vue-property-decorator';
export default class MyComponent extends Vue {
@PropSync('title', { type: String }) syncedTitle!: string;
}
3.4 @Model
- 用途 :自定义
v-model
的 prop 和事件(默认value
+input
)。 - 对比:
typescript
// Options API
model: {
prop: 'checked',
event: 'change'
},
props: ['checked']
// vue-property-decorator
import { Model } from 'vue-property-decorator';
export default class MyComponent extends Vue {
@Model({ type: Boolean, event: 'change' }) checked!: boolean;
}
3.5 @Watch
- 用途:监听数据变化,执行回调。
- 对比:
typescript
// Options API
watch: {
count(newVal) { console.log('Count changed:', newVal); }
}
// vue-property-decorator
import { Watch } from 'vue-property-decorator';
export default class MyComponent extends Vue {
@Watch('count')
onCountChanged(newVal: number) {
console.log('Count changed:', newVal);
}
// 监听深度对象或立即触发
@Watch('obj', { immediate: true, deep: true })
onObjChanged(newVal: any) { /* ... */ }
}
3.6 @Emit
- 用途:触发自定义事件,自动处理事件名和返回值。
- 对比:
typescript
// Options API
methods: {
submit() { this.$emit('submit', data); }
}
// vue-property-decorator
import { Emit } from 'vue-property-decorator';
export default class MyComponent extends Vue {
@Emit('submit')
submit() {
return data; // 返回值作为事件参数
}
// 若方法名与事件名相同,可省略参数
@Emit()
cancel() { /* 无需返回 */ } // 触发 'cancel' 事件
}
3.7 @Inject
与 @Provide
- 用途 :依赖注入(替代 Vue 的
provide/inject
)。 - 对比:
typescript
// Options API (父组件)
provide() {
return { theme: 'dark' };
}
// Options API (子组件)
inject: ['theme']
// vue-property-decorator (父组件)
import { Provide } from 'vue-property-decorator';
export default class Parent extends Vue {
@Provide() theme = 'dark';
}
// vue-property-decorator (子组件)
import { Inject } from 'vue-property-decorator';
export default class Child extends Vue {
@Inject() theme!: string;
}
3.8 @Ref
- 用途:引用 DOM 元素或子组件实例。
- 对比:
typescript
// Options API
methods: {
focusInput() {
this.$refs.inputRef.focus();
}
}
// vue-property-decorator
import { Ref } from 'vue-property-decorator';
export default class MyComponent extends Vue {
@Ref() inputRef!: HTMLInputElement;
focusInput() {
this.inputRef.focus();
}
}
3.9 @Mixins
- 用途 :混入多个类(替代 Vue 的
mixins
选项)。 - 对比:
typescript
// Options API
import MixinA from './mixinA';
import MixinB from './mixinB';
export default {
mixins: [MixinA, MixinB]
}
// vue-property-decorator
import { Mixins } from 'vue-property-decorator';
import MixinA from './mixinA';
import MixinB from './mixinB';
@Component
export default class MyComponent extends Mixins(MixinA, MixinB) {}
4. 完整对比
装饰器 | Options API 等效写法 | 装饰器语法示例 | 核心优势 |
---|---|---|---|
@Component |
export default { components, mixins... } |
@Component({ components: { Child } }) |
集中配置组件选项 |
@Prop |
props: { ... } |
@Prop({ type: String }) title!: string |
类型明确的 Props 声明 |
@PropSync |
computed + $emit |
@PropSync('title') syncedTitle!: string |
简化双向绑定逻辑 |
@Model |
model: { prop, event } |
@Model('change') checked!: boolean |
自定义 v-model 行为 |
@Watch |
watch: { ... } |
@Watch('count') onCountChanged() |
声明式监听,支持深度/立即监听 |
@Emit |
this.$emit('event') |
@Emit() submit() { return data } |
自动生成事件触发逻辑 |
@Inject /@Provide |
provide() /inject: [...] |
@Provide() theme = 'dark' |
类型安全的依赖注入 |
@Ref |
this.$refs.xxx |
@Ref() inputRef!: HTMLInputElement |
明确的类型引用 |
@Mixins |
mixins: [MixinA, MixinB] |
extends Mixins(MixinA, MixinB) |
结构更清晰 |
5. 总结
vue-property-decorator 让 Vue 2 开发更好的 TypeScript 支持,类型检查更严格,代码结构更简洁,逻辑集中,装饰器语法更符合面向对象编程习惯。