前言:在不了解vue+ts的情况下,跟着项目一葫芦画瓢,created/mounted等钩子怎么都不执行的问题
解决方案:需要引入component模块,此时,mounted/created才会执行(注意是在export外面),@Component修饰符注明了此类Vue组件
链接: vue3+ts
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
@Component
export default class Register(组件名) extends Vue {
mounted() {
console.log("mounted")
}
created() {
console.log("created")
}
}
</script>
引入Typescript
npm install vue-class-component vue-property-decorator --save
npm install ts-loader typescript tslint tslint-loader tslint-config-standard --save-dev
// vue-class-component:扩展vue支持typescript,将原有的vue语法通过声明的方式来支持ts
// vue-property-decorator:基于vue-property-decorator更多装饰器
// ts-loader:让webpack能够识别ts文件
// tslint-loader:tslint用来约束文件编码
// tslint-config-standard:tslint配置standard风格的约束
配置文件:
webpack配置
项目不同会有稍许差异,vue3.0在vue.config.js中配置,3.0以下在webpack.base.conf中配置
1、在webpack.prod.config.js
resolve: {
extensions: [".ts", ".js", ".vue", ".json"],
alias: {}
}
在module rules中增加ts的rules
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
enforce: 'pre',
loader: 'tslint-loader'
},
{
test: /\.tsx?$/,
loader: 'ts-loader',
exclude: /node_modules/,
options: {
appendTsSuffixTo: [/\.vue$/]
}
}
]
}
tsconfig.json配置
{
"include": ["src/app/view/pages/*", "src/index.ts", "src/vue-shim.d.ts"],
"exclude": ["node_modules", "src/app/assets/**/*"],
"compilerOptions": {
"allowSyntheticDefaultImports": true, // 允许从没有设置默认导出的模块中默认导入
"experimentalDecorators": true, // 启用装饰器
"allowJs": true, // 允许编译javascript文件
"module": "esnext", // 采用的模块系统
"target": "es5", // 编译输出目标es5版本
"moduleResolution": "node", // 如何处理模块
"isolatedModules": true, // 将每个文件座位单独的模块
"lib": ["dom", "es5", "es2015.promise"], // 编译过程中需要引入的库文件的列表
"sourceMap": true, // 是否包含可以用于debug的sourceMap
"pretty": true
}
}
项目识别.ts
TypeScript默认不支持*.vue后缀的文件,自己在项目的根目录src文件夹下创建一个vue-shim.d.ts
declare module "*.vue" {
import Vue from "vue";
export default Vue;
}
vue-property-decorator
组件依赖于vue-class-component,它具备以下几个属性:
@Component(完全继承于vue-class-component)
@Emit
@inject
@Provice
@Prop
@Watch
@Model
Mixins(在vue-class-component中定义)
vue组件的编写
vue组件里大多数的方法改成通过@xxx(装饰器)来表明当前定义的数据
基本写法:
模板template和样式style的写法不变,script模块进行改变,基本写法如下:
// lang="ts": script声明当前语言是ts
// @Component: 注明此类为一个vue组件
// export default class Test extends Vue: export当前组件类是继承Vue的
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
@Component
export default class Test extends Vue {
}
</script>
1、data()中定义数据
data中的数据由原来的data()方法改成直接在对象中定义
export default class Text extends Vue {
// public 也可省略
public message1: string = "hello"
public message2: boolean = true
}
2、props传值
@Prop({default:{}}) docOpen!: Object;
@Prop({default:true}) showHead: boolean;
@Prop() propname: number
// !表示一定存在, ?:表示可能不存在。这两种在语法上叫赋值断言
// @Prop(options: (PropOptions | Constructor[] | Constructor) = {})
/// PropOptions ,可以使用以下选项: type,default, required, validator
/// Constructor[], 指定prop的可选类型
/// Constructor
3、$emit传值
// 原来写法 this.$emit('bindSend')
// 现在直接写成 this.bindSend()
// 多个定义
//1:不带参数
@Emit()
bindSend1(): string {
return this.message
}
// 2:方法带参
@Emit()
bindSend2(msg: string) {
}
// emit带参数
// 这里的test是改变组件引用引用的@事件名称这时要写@test,不写成@bindSend2
@Emit('test')
private bindSend3() {
}
// 示例
// 原来是这个样子的
clickMsg() {
this.svalue = '123'
this.$emit('change-msg', 'ddd')
}
// 当前组件
<div @click="clickMsg"></div>
// 父组件
<hello-world :msg="msg" @change-msg="handleChangeMsg"/>
handleChangeMsg(value) {
this.msg = value
}
// ts中这样的写法
@Emit('change-msg')
clickMsg() {
this.svalue = '123' // 组件本身的逻辑
return 'ddd' // emit的第二个参数,也就是父组件的值
}
// @Emit(event?: string)
// @Emit装饰器接受一个可选参数,该参数是emit的第一个参数,充当事件名,没有提供这个参数的话,Emit会将回调函数名的camelCase转为kebab-case,并将其作为事件名
// @Emit会将回调函数的返回值作为第二个参数,如果返回值是一个Promise对象,$emit会在Promise对象被标记为resolved之后触发
// @Emit的回调函数的参数,会放在其返回值之后,一起被$emit当做参数使用
4、watch
// watch函数和参数分为两部分,函数名必须是on[key]Change
@Watch("name", { immediate: true, deep: true })
private onNameChange(newValue: string, oldValue: string) {
console.log("watch", newValue, oldValue)
}
// @Watch(path: string, options: WatchOptions = {})
// options包含两个属性immediate?: boolean 侦听开始之后是否立即调用该函数;deep?: boolean 是否深度监听
// @Watch('arr', {immediate: true, deep: true}) onArrChanged(newValue: number[], oldValue: number[]) {}
5、computed
// computed就是普通方法前面加get,表示此属性是计算来的<div>{{allname}}</div>
public get allname() {
return 'computed' + this.name
}
set allname(newValue) {
this.name = newValue.slice(8)
}
6、methods
直接写就行
export default class Test extends Vue {
// <div @click="clickName">dd</div>
clickName() {
}
}