续:组件声明
之前说到了 vue 的组件如果换用 TypeScript 环境,各个选项模块声明方法也有所变化,已经说明了 data
, methods
, computed
选项属性,这里继续列举说明。
另外,补充说明一点,vue 中 data 选项在 JS 中的一般写法为函数形式:data() { return {} }
。这种写法的好处是可以避免在复用组件时,发生多组件共用 data 数据库,数据的污染和混淆。每次 return 都会在该组件内生成一个独立空间存储数据,避免混用。之前提到,在 TS 中 data
可以直接使用定义变量的形式声明,我一开始也有疑惑会不会相当于是没有使用 return 形式的 data ,结果查阅一些资料,证明了 TypeScript 中变量形式的声明就相当于是 return{} 函数返回值,不需要担心数据污染问题,书写也很简洁了。
props 写法
该组件在父组件模板中如:
<name-list msg="小李">
接受父组件传递的 props:
export default class NameList extends Vue {
@Prop({ default: "" }) readonly msg!: string;
}
- 在 TypeScript 中,
!:
表示一定存在,?:
表示可能不存在。这两种在语法上叫赋值断言,是 TS 中非常重要的语法。 - 需要注意的是,
@Prop()
的括号内只允许接受一个参数,如果要输入多个参数,需要包裹成一个对象。
prop 可以接受的参数如下:
@Prop(options: (PropOptions | Constructor[] | Constructor) = {})
- PropOptions,可以使用以下选项:type,default,required,validator
- Constructor[],指定 prop 的可选类型
- Constructor,例如 String,Number,Boolean 等,指定 prop 的类型
watch 写法
监听方法 watch 的写法就复杂一些,需要注意一下:
-
属性参数 @Watch(path: string, options: WatchOptions = {})
-
options 包含两个属性 immediate?:boolean 侦听开始之后是否立即调用该回调函数; deep?:boolean 被侦听的对象的属性被改变时,不论其被嵌套多深,调用该回调函数,即深度监听。
-
options 的两个属性不写默认为
false
-
watch声明写法,函数和参数分为两部分,函数名必须是
on[key]Change
这种形式。 -
@Watch('arr', { immediate: true, deep: true }) onNameChanged(newValue: string[], oldValue: string[]) {} 可以接受旧值和新值并执行回调函数。
如:
export default class NameList extends Vue {
@Watch("name", { immediate: true, deep: true })
private onNameChange(newValue: string, oldValue: string) {
console.log("watch", newValue, oldValue);
} }
生命周期函数写法
export default class HelloWorld extends Vue {
// created生命周期函数
public created(): void {}
// mounted生命周期函数
public mounted(): void {}
}
写法跟在 JS 中一模一样,没什么需要好说的。
顺带提一句,在 TS 中,类中方法的修饰符默认就是 public
,声明可以被他人调用。
Ref 写法
- 属性参数:@Ref(refKey?: string)
@Ref 装饰器接收一个可选参数,用来指向元素或子组件的引用信息。如果没有提供这个参数,会使用装饰器后面的属性名充当参数。
<HelloWorld ref="addButton"></HelloWorld>
import { Component, Vue, Ref } from 'vue-property-decorator';
import HelloWorld from "@/components/HelloWorld.vue";
@Component({ components: { HelloWorld } })
export default class App extends Vue {
@Ref('RefComponent') readonly ref!: HTMLDocument;
getRef() {
this.$refs.RefComponent.mothed();
// mothed 为子组件中定义的方法
}
}
emit 写法
emit 的写法也比较复杂一点。
-
属性参数:@Emit(event?: string) 参数说明:
-
@Emit 装饰器接收一个可选参数,充当事件名。如果没有提供这个参数,@Emit会将回调函数名的camelCase转为kebab-case,并将其作为事件名
-
@Emit会将回调函数的返回值作为第二个参数,如果返回值是一个Promise对象,$emit会在Promise对象被标记为resolved之后触发。
-
@Emit的回调函数的参数,会在回调函数没有返回值的情况下,被
$emit
当做第二个参数使用;有返回值,会放在其返回值之后,一起被$emit
当做参数使用
//当前子组件
<div @click="clickMsg"/>
// 相当于 JS 写法的
clickMsg(){
this.$emit('change-msg','jack');
}
//父组件中
<hello-world :msg="msg" @change-msg="handleChangeMsg"/>
handleChangeMsg(value){ this.msg = value }
// TS 写法父组件一致,只是子组件的区别
import { Component, Prop, Emit } from 'vue-property-decorator';
export default class HelloWorld extends Vue {
@Emit("change-msg")
clickMsg() {
// $emit的第二个参数,也就是给父组件的值
return "jack";
}
}
比较绕,写几个例子试验下就清晰了。实际上不适用这种写法,使用传统的 $emit 也是没问题的。
@Model (V-Model)
默认情况下,一个组件上的v-model
会把 value
用作 prop
,并把 input
用作 event
,但是一些输入类型比如单选框和复选框按钮可能想使用不同的 value prop 组合来达到不同的目的。使用model
选项可以回避这些情况产生的冲突。
下面是Vue官网的例子:
Vue.component('base-checkbox', {
model: { prop: 'checked', event: 'change' },
props: { checked: Boolean },
template: ` <input type="checkbox"
v-bind:checked="checked"
v-on:change="$emit('change', $event.target.checked)" > `
})
在这个组件上使用 v-model
的时候:
<base-checkbox v-model="lovingVue"></base-checkbox>
注意:你仍然需要在组件的 props 选项里声明 checked 这个 prop。
使用vue-property-decorator
提供的@Model
改造上面的例子,在自定义组件中:
import { Component, Prop, Model } from 'vue-property-decorator';
export default class BaseCheckbox extends Vue {
@Model('change', {type: Boolean}) checked!: boolean;
}
mixin 混入
在 TypeScript 中写 mixin ,mixin 本身是个 .ts 文件,需要注意。然后在文件内部通过 export 来进行类的导出,然后在 vue 文件中引入得到抽离出来的公共部分。
MyMixin.ts 写法:
import Vue from 'vue';
import { Component, Prop } from 'vue-property-decorator';
import MyMixins from './MyMixin';
@Component export default class MyMixin extends Vue {
@Prop({ required: true }) structure: AnyObj;
created(): void { // ... }
}
使用 mixins 的文件:
import { Component, Prop, Mixins } from 'vue-property-decorator';
import MyMixins from './MyMixin';
@Component export default class App extends Mixins(MyMixin) {
// ... }
需要写两个或更多 mixins 的话,在 Mixins 里面继续添加即可。通过 Mixins 引入可以正常使用 TS 的语法检测系统,用起来也不复杂。
常用的组件声明就这些,先分享这么多,如有更多内容未来补充。