Vue2 项目如何让代码更优雅(vue-property-decorator 的使用)

大家好,我是格子,今天写这个文章的目的是为了,以后如果遇到 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-decoratorvue-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 支持,类型检查更严格,代码结构更简洁,逻辑集中,装饰器语法更符合面向对象编程习惯。

相关推荐
前端小同学1 分钟前
【硬核开源mcp-chrome】一个chrome插件,能让任意chatbot接管你的chrome浏览器
前端·人工智能
Uyker11 分钟前
解读Qwin
前端
月忆36439 分钟前
等待组(waitgroup)
前端·爬虫·python
令狐寻欢42 分钟前
HTML中 的 meta 标签常用属性及其作用
前端·html
SynthWriter1 小时前
Trae 帮我生成了一个贪吃蛇的游戏,好玩儿
前端
用户21411832636021 小时前
dify案例分享-Dify+RSS 聚合 8 大平台实时热点,新闻获取效率飙升 300%
前端
百锦再1 小时前
Razor编程中@Html的方法使用大全
前端·html
啪叽1 小时前
JavaScript可选链操作符(?.)的实用指南
前端·javascript
Ian在掘金1 小时前
bat+python实现easy connect自动连接
前端·python
代码搬运媛1 小时前
【react实战】如何实现监听窗口大小变化
前端·javascript·react.js