前言
在Vue中使用typescript,通过使用vue-property-decorator装饰器来简化书写。
装饰器
- @Component
- @Emit
- @Prop
- @PropSync
- @Watch
- @Inject
- @Provide
- @Model
- @Ref
- Mixins
@Component 声明组件
import { Vue,Component } from 'vue-property-decorator'
import {componentA} from '@/components'
@Component({
components: {componentA} // 其他组件声明
})
// @Component
export default class '组件名' extends Vue {
private valueA: string = '我是ValueA' // data里的变量
private valueB: number[] = [1,2,3]
private get valueC () { // 计算属性,相当于getter
return 1
}
public render() {
return (<div>...</div>)
}
}
等同于
<script lang="es6">
import Vue from 'vue';
export default {
data(){
return {
ValA: '我是ValueA',
ValB: [1,2,3]
}
},
computed: {
valueC: function() {
return 1;
}
}
}
</script>
总结: 对于
data
里的变量,直接按ts定义类变量的写法写即可
@Emit 事件触发
// 子组件
@Emit() // 参数为父组件绑定事件名,不写默认跟随的函数名称[这种情况下,camelCase名称将转换为kebab-case]
private emitChange() {
return 'something' // 如果想返回值,可以这边return
}
@Emit('reset')
private emitChange1() {
return 'something' // 如果想返回值,可以这边return
}
// 父组件
<child onReset={(res: any) => this.parentHandleChange(res)}>
<script lang="ts">
import {Vue, Component, Emit} from 'vue-property-decorator';
@Component({})
export default class '组件名' extends Vue{
mounted(){
this.$on('emit-todo', function(what) {
console.log(waht)
})
this.emitTodo('接收');
}
@Emit()
emitTodo(what: string){
console.log('发送emitTodo');
}
}
</script>
等同于
<script lang="es6">
import Vue from 'vue';
export default {
mounted(){
this.$on('emit-todo', function(what) {
console.log(what)
})
this.emitTodo('接收');
},
methods: {
emitTodo(what){
console.log('发送emitTodo');
this.$emit('emit-todo', what);
}
}
}
</script>
@Emit
不传参,那么它触发的事件名就是他所修饰的函数名@Emit(name: string)
里面传递一个字符串,该字符串为要触发的事件名
@Watch 值监听变化
watch方法需要声明在变量和jsx之后
<script>
export default{
watch: {
'child': this.onChangeValue
// 这种写法默认 `immediate`和`deep`为`false`
,
'person': {
handler: 'onChangeValue',
immediate: true,
deep: true
}
},
methods: {
onChangeValue(newVal, oldVal){
// todo...
}
}
}
</script>
@Watch的用法
import {Vue, Component, Watch} from 'vue-property-decorator';
@Watch('child')
onChangeValue(newVal: string, oldVal: string){
// todo...
}
@Watch('person', {immediate: true, deep: true})
onChangeValue(newVal: Person, oldVal: Person){
// todo...
}
@Watch
接受第一个参数为要监听的属性名 第二个属性为可选对象.@Watch
所装饰的函数即监听到属性变化之后的操作.
@Prop
<script>
// javascript的vue写法
export default {
props: {
propA: {
type: Number
},
propB: {
default: 'default value'
},
propC: {
type: [String, Boolean]
},
}
}
</script>
ts改造如下
<script lang="ts">
import {Vue, Component, Prop} from 'vue-property-decorator';
@Component({})
export default class '组件名' extends Vue{
@Prop(Number) propA!: number;
@Prop({default: 'default value'}) propB!: string;
@propC([String, Boolean]) propC: string | boolean;
}
</script>
!
代表必填参数,?
代表可选参数
@Prop
接受一个参数可以是类型变量或者对象或者数组.@Prop
接受的类型比如Number
是JavaScript
的类型,之后定义的属性类型则是TypeScript
的类型.
mixins
// mixins.ts
export default class MyMixins extends Vue{
value: string ='hi'
}
// 引入
// 方法一 vue-class-component提供
import {mixins} from 'vue-class-component'
import myMixins from 'mixin.ts'
@Componnet
export default class myCom extends mixins(myMixins){
public create () {
console.log(this.value)
}
}
// 方法二 @Component中混入
// mixins.ts
declare module 'vue/types/vue' {
interface Vue {
value: string
}
}
@Component
export default class myMixins extends Vue {
value: string = 'hello'
}
// 引入
@Component({
mixins: [myMixins]
})
export default class myCom extends mixins(myMixins){
public create () {
console.log(this.value)
}
}
- 两种方式不同的是在定义
mixins
时如果没有定义vue/type/vue
模块, 那么在混入的时候就要继承
该mixins
; 如果定义vue/type/vue
模块,在混入时可以在@Component
中mixins
直接混入.
@Model
Vue
组件提供model: {prop?: string, event?: string}
让我们可以定制prop
和event
.
默认情况下,一个组件上的v-model
. 会把value
.用作prop
且把input
用作event
,但是一些输入类型比如单选框和复选框按钮可能想使用value prop
来达到不同的目的。使用model
选项可以回避这些情况产生的冲突。
-
首先看看Vue官网的例子
Vue.component('my-checkbox', { model: { prop: 'checked', event: 'change' }, props: { // this allows using the `value` prop for a different purpose value: String, // use `checked` as the prop which take the place of `value` checked: { type: Number, default: 0 } }, // ... })
<my-checkbox v-model="foo" value="some value"></my-checkbox>
上述代码相当于:
<my-checkbox
:checked="foo"
@change="val => { foo = val }"
value="some value">
</my-checkbox>
即foo
双向绑定的是组件的checked
, 触发双向绑定数值的事件是change
使用vue-property-decor
提供的@Model
改造上面的例子.
import { Vue, Component, Model} from 'vue-property-decorator';
@Component
export class myCheck extends Vue{
@Model ('change', {type: Boolean}) checked!: boolean;
}
@Model()
接收两个参数, 第一个是event
值, 第二个是prop
的类型说明, 与@Prop
类似.
@Provide提供/@Inject注入
父组件不便于向子组件传递数据,就把数据通过provide传递下去,然后子组件通过Inject来获取
// js写法
data() {return {foo: 'foo'}}
provide() {
return { foo, this.foo}
}
inject: {
}
// ts
import {Vue,Component,Inject,Provide} from 'vue-property-decorator'
@Component
export defalut class MyComponent extends Vue{
@Inject()
foo!: string
@Inject('bar')
bar!: string
@Inject({ from:'optional', default:'default'})
optional!: string;
@Provide()
foo = 'foo'
@Provide('bar')
baz = 'bar'
}
@Ref
(refKey?: string) decorator
import { Vue, Component, Ref } from 'vue-property-decorator'
import AnotherComponent from '@/path/to/another-component.vue'
@Component
export default class YourComponent extends Vue {
@Ref() readonly anotherComponent!: AnotherComponent
@Ref('aButton') readonly button!: HTMLButtonElement
}
等同于
export default {
computed() {
anotherComponent: {
cache: false,
get() {
return this.$refs.anotherComponent as AnotherComponent
}
},
button: {
cache: false,
get() {
return this.$refs.aButton as HTMLButtonElement
}
}
}
}
@PropSync暂时没有用到。