由于项目需要,需要使用Vue
的class语法配合TypeScript
来进行组件开发,我也简单总结了一下Class语法与常规语法的对照,便于记忆和查阅。
项目中使用的是vue-class-component
、vue-property-decorator
配合TypeScript
来进行开发的,其中vue-class-component
提供了class语法,而vue-property-decorator
提供了一些装饰器来方便代码的组织和编写。
下面我将一一对照class语法与常规语法,希望能够方便各位读者的使用和记忆,更多详细信息,请参考下面的官方网站或者github文档:
注意:我将按照Vue
官方风格指南推荐的顺序来进行一一对照,包含绝大多数常用写法:
components
Class语法:
import { Component, Vue } from 'vue-property-decorator'
import { CreateElement } from 'vue'
import Game from '../../components/game'
@Component({
components: {
game: Game
}
})
export default class Test extends Vue {
...
}
常规语法:
import Game from '../../components/game'
export default {
components: {
game: Game
}
...
}
model
注意:model属性实际对应的是在Vue
中常用的指令v-model
,通常v-model
用于名为value
的prop和名为input
的事件,但是对于单选框、复选框等类型的输入控件并不适用,通过model
可以达到这个目的。由于v-model
实际上是通过事件监听的方式实现的语法糖,使用model
属性用于单选框、复选框等类型的控件,简化了语法。
Class语法:
import { Vue, Component } from 'vue-property-decorator'
@Component
export default class Game extends Vue {
@Model('change', { type: Boolean }) readonly checked!: boolean
...
}
常规语法:
export default {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: {
type: Boolean
}
}
}
props
注意:下方的readonly
和: string | undefined
属于TypeScript
语法,用于设置player属性只读,并设置player属性的类型为 string或者undefined。
Class语法:
import { Vue, Component, Prop } from 'vue-property-decorator'
@Component
export default class Game extends Vue {
@Prop(String) readonly player: string | undefined
...
}
常规语法:
export default {
props: {
player {
type: String
}
}
}
data
注意:data中的属性在class语法中被定义为了类的属性,但是由于在初始化的时候已经赋值,所以不需要再为属性设置类型,TypeScript
会推断出属性的类型(其中数组results设置了数组元素的类型)。
class语法:
import { Vue, Component } from 'vue-property-decorator'
@Component
export default class Game extends Vue {
// 定义data
private selectOptions = ['石头', '剪刀', '布']
private results: string[] = []
private grade = 0
private round = 1
private playerSelected = ''
...
}
常规语法:
export default {
data(){
return {
selectOptions: ['石头', '剪刀', '布'],
results: [],
grade: 0,
round: 1,
playerSelected: '',
}
}
}
computed
class语法:
import { Vue, Component } from 'vue-property-decorator'
@Component
export default class HelloWorld extends Vue {
private firstName = 'Mark'
private lastName = 'Twain'
// 定义为计算属性的getter
get name() {
return this.firstName + ' ' + this.lastName
}
// 定义为计算属性的setter
set name(value) {
const splitted = value.split(' ')
this.firstName = splitted[0]
this.lastName = splitted[1] || ''
}
}
常规语法:
export default {
data () {
return {
firstName: 'Mark',
lastName: 'Twain',
}
},
computed: {
name: {
get: function() {
return this.firstName + ' ' + this.lastName
},
set: function(value) {
const splitted = value.split(' ')
this.firstName = splitted[0]
this.lastName = splitted[1] || ''
}
}
}
}
watch
class语法:
import { Vue, Component, Watch } from 'vue-property-decorator'
@Component
export default class MyClass extends Vue {
@Watch('child')
onChildChanged(val: string, oldVal: string) {}
@Watch('person', { immediate: true, deep: true })
onPersonChanged1(val: Person, oldVal: Person) {}
@Watch('person')
onPersonChanged2(val: Person, oldVal: Person) {}
}
常规语法:
export default {
watch: {
child: [
{
handler: 'onChildChanged',
immediate: false,
deep: false
}
],
person: [
{
handler: 'onPersonChanged1',
immediate: true,
deep: true
},
{
handler: 'onPersonChanged2',
immediate: false,
deep: false
}
]
},
methods: {
onChildChanged(val, oldVal) {},
onPersonChanged1(val, oldVal) {},
onPersonChanged2(val, oldVal) {}
}
}
生命周期钩子函数
注意:生命周期钩子函数包括:beforeCreate、created、beforeMounted、mounted、beforeUpdate、updated、activated、deactivated、beforeDestory、destoryed、errorCaptured;下面不会一一举例,只会列出其中几个,因为它们的class语法类似(用法不同)。
class语法:
注意:class
语法中,生命周期钩子函数被定义为了类的方法。
import { Vue, Component } from 'vue-property-decorator'
@Component
export default class MyClass extends Vue {
private mounted() {
console.log('mounted')
},
private updated() {
console.log('updated')
}
}
常规语法:
export default {
mounted() {
console.log('mounted')
},
updated() {
console.log('updated')
}
}
methods
class语法:
注意:class
语法中,methods中定义的方法被定义为了类的方法。
import { Vue, Component } from 'vue-property-decorator'
@Component
export default class MyClass extends Vue {
private clog(msg: string){
console.log(msg)
}
}
常规语法:
export default {
methods: {
clog(msg) {
console.log(msg)
}
}
}
render
注意:通过render函数,可以代替字符串模板,该渲染函数接收一个 createElement 方法作为第一个参数用来创建 VNode。
class语法:
注意:class
语法中,render配合jsx
语法时需要配合相关插件使用@vue/babel-preset-jsx @vue/babel-
、helper-vue-jsx-merge-props
,但是如果项目是使用vue-cli创建的就不需要额外安装这两个插件,脚手架中已默认集成并配置。
import { Vue, Component } from 'vue-property-decorator'
@Component
export default class MyClass extends Vue {
private render() {
const jsx = ...
return jsx
}
}
常规语法:
export default {
render: function (createElement, context) {
...
}
}
provide / inject
注意:这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深;所以在一般的组件中并不适合使用,使用开发高阶插件/组件库。
class语法:
import { Component, Inject, Provide, Vue } from 'vue-property-decorator'
const symbol = Symbol('baz')
@Component
export class MyComponent extends Vue {
@Inject() readonly foo!: string
@Inject('bar') readonly bar!: string
@Inject({ from: 'optional', default: 'default' }) readonly optional!: string
@Inject(symbol) readonly baz!: string
@Provide() foo = 'foo'
@Provide('bar') baz = 'bar'
}
常规语法:
const symbol = Symbol('baz')
export const MyComponent = Vue.extend({
inject: {
foo: 'foo',
bar: 'bar',
optional: { from: 'optional', default: 'default' },
[symbol]: symbol
},
data() {
return {
foo: 'foo',
baz: 'bar'
}
},
provide() {
return {
foo: this.foo,
bar: this.baz
}
}
})
Emit
注意:这个实际上是用来触发当前实例上的事件的方法。 class语法:
import { Vue, Component, Emit } from 'vue-property-decorator'
@Component
export default class YourComponent extends Vue {
count = 0
@Emit()
addToCount(n: number) {
this.count += n
}
@Emit('reset')
resetCount() {
this.count = 0
}
@Emit()
returnValue() {
return 10
}
@Emit()
onInputChange(e) {
return e.target.value
}
@Emit()
promise() {
return new Promise(resolve => {
setTimeout(() => {
resolve(20)
}, 0)
})
}
}
常规语法:
export default {
data() {
return {
count: 0
}
},
methods: {
addToCount(n) {
this.count += n
this.$emit('add-to-count', n)
},
resetCount() {
this.count = 0
this.$emit('reset')
},
returnValue() {
this.$emit('return-value', 10)
},
onInputChange(e) {
this.$emit('on-input-change', e.target.value, e)
},
promise() {
const promise = new Promise(resolve => {
setTimeout(() => {
resolve(20)
}, 0)
})
promise.then(value => {
this.$emit('promise', value)
})
}
}
}
mixins
注意:mixins接收一个对象数组,其中的对象是包含vue选项(created、data、computed等)的对象,mixins中的对象会按照一定的规则与当前组件中的选项进行合并或者替换(同一类型相同名称的选项中,原有的选项会覆盖mixins中的选项)。
class语法:
声明mixins Hello和的示例World:
// mixins.js
import Vue from 'vue'
import Component from 'vue-class-component'
// You can declare mixins as the same style as components.
@Component
export class Hello extends Vue {
hello = 'Hello'
}
@Component
export class World extends Vue {
world = 'World'
}
在类样式组件中使用它们:
import Component, { mixins } from 'vue-class-component'
import { Hello, World } from './mixins'
// Use `mixins` helper function instead of `Vue`.
// `mixins` can receive any number of arguments.
@Component
export class HelloWorld extends mixins(Hello, World) {
created () {
console.log(this.hello + ' ' + this.world + '!') // -> Hello World!
}
}
常规语法:
声明mixins Hello和的示例World:
// mixins.js
export default {
data() {
return {
hello: 'Hello',
world: 'World'
}
}
}
在类样式组件中使用它们:
import { Hello, World } from './mixins'
export default {
created() {
console.log(this.hello + ' ' + this.world + '!') // -> Hello World!
},
mixins: [mixin]
}