前端技术之---class-style Vue写法

前言

在一些 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 组件对应的 datacomputedmethods 等配置。

二、为什么会有 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>