typescript引入

新建项目
创建项目时,选择ts
在这里插入图片描述已存在项目

vue add @vue/typescript

在这里插入图片描述

项目内使用

状态管理
vuex-module-decorators通过装饰器提供模块化声明vuex模块的方法,可以有效利用ts的类型系统
安装

npm i vuex-module-decorators -D

vuex-module-decorators git地址
src/store/index.ts

import Vuex from 'vuex'
import Vue from 'vue'
Vue.use(Vuex)
export default new Vuex.Store({})

src/store/counter.ts

import {Module, VuexModule, Mutation, Action, getModule} from 'vuex-module-decorators'
import store from '@/store'
//动态注册模块
@Module({dynamic:true,store,name:'Counter',namespaced:true})
//es6定义类的方式
export default class Counter extends VuexModule{
    count = 1
    @Mutation
    add(){
        this.count++
    }
    //存取器,相当于getters
    get doubleCount(){
        return this.count*2
    }
    @Action
    asyncAdd(){
        setTimeout(()=>{
            this.add()
        },1000)
    }
}
//导出模块应该是getModule的结果
export const CountModule = getModule(Counter)

main.ts中引入

import store from './store'
new Vue({
  render: h => h(App),
  store
}).$mount('#app')

创建类型声明文件
src/types/index.ts

//类型声明
export type Info = {
    id: number
    name: string
}
//交叉类型
export type Infolist = Info & {selected:boolean}
//泛型
export interface Result<T>{
    code:number,
    data:T
}

组件内部语法变更
父组件

<template>
  <div class="hello">
    <p>{{content}}</p>
   	<p @click="add">{{$store.state.Counter.count}}</p>
    <p @click="asyncAdd">{{count}}</p>
    <TsTest msg="hello typescript" @add-list="onClick"></TsTest>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import {CountModule} from '@/store/counter'
@Component({
  components:{
    //导入子组件需要加入./确定为当前目录,否则因为设置别名的原因会找不到文件
    //懒加载导入组件
    TsTest:()=>import('./tstest/index.vue')
  }
})
export default class HelloWorld extends Vue {
  //接收子组件传过来的值
  content = "asd"
  onClick(res:any){
    this.content = res.name
  }
  //组件内使用vuex方法
  get count(){
    return CountModule.count
  }
  add(){
    CountModule.add()
  }
  asyncAdd(){
    CountModule.asyncAdd()
  }
}
</script>

<style scoped>

</style>

子组件

<template>
    <div>
        <h2>{{msg}}</h2>
        <p>{{foo}}</p>
        <input type="text" @keydown.enter="addList">
        <ul>
            <li v-for="item in list" :key="item.id" :class="{selected:item.selected}">{{item.name}}</li>
        </ul>
        <p>总数{{count}}</p>
    </div>
</template>

<script lang="ts">
    import { Prop, Component, Vue, Emit, Watch } from 'vue-property-decorator';
    //导入类型和接口
    import {Infolist,Result} from '@/types'
    //泛型方法
    function getList<T>(): Promise<Result<T>>{
        const data: any = [{
            id:1,
            name:"aaa",
            selected: false
        },{
            id:2,
            name:"bbb",
            selected: true
        }]
        return Promise.resolve({
            code:200,
            data
        })
    }

    @Component
    export default class TsTestOne extends Vue {
        //装饰器,内部可传参
        @Prop()
        msg!:string
        //数据定义
        foo = "foo"
        list:Infolist[] = []
        //生命周期
        async created(){
            this.list = (await getList<Infolist[]>()).data  
        }
        mounted(){
            this.foo = "welcome to 临涧村"
        }
        //事件
        //向父组件传值
        //装饰器中的参数为事件名,若为指定则函数名为事件名,父组件中需要以羊肉串命名方式去添加
        @Emit()
        addList(e: KeyboardEvent):Infolist{//若没有返回值,形参将作为事件参数
            //类型断言
            const inp = e.target as HTMLInputElement
            const item: Infolist = {
                id: this.list.length + 1,
                name: inp.value,
                selected: false
            }
            this.list.push(item)
            inp.value = ""
            return item;//存在返回值,返回值作为事件参数
        }
        
        //存取器作为计算属性
        get count(){
            return this.list.length
        }
        //watcher监听
        @Watch("list")
        onListChange(newVal:Infolist[],oldVal:Infolist[]){
            console.log(newVal)
        }
    }
</script>

<style scoped>
    .selected{
        background: #ccc;
    }
</style>

声明文件

要使用第三方js库,同时还想利用ts类型检查特性,就需要用到声明文件
类似xx.d.ts
如需要使用vue-router,就在router目录下新建index.d.ts

import VueRouter from 'vue-router'
declare const router: VueRouter
export default router

装饰器原理

常用装饰器用法
用于扩展类或者它的属性和方法
装饰器本质就是一个工厂函数,能访问或修改装饰目标

//类装饰器
//类装饰器表达式会在运行时当做函数被调用
//类的构造函数作为其唯一参数
function log(target:Function){
    target.prototype.log = function(){
        console.log(this.bar)
    }
}
//方法装饰器
/*
 descriptor为属性描述符
 {
    value: 属性值,
    enumerable: false, // 是否可枚举
    configurable: true, // 是否可配置
    writable: true // 是否可写
 }
*/
function rec(target:any,name:string,descriptor:any){
    //通过修改descriptor.value扩展bar方法
    const baz = descriptor.value;
    descriptor.value = function(val:string){
        console.log('run method',name)//run method setBar
        baz.call(this,val)
    }
}
//属性装饰器
function msg(target:any,name:string){
    target[name] = "bbb"
}
@log
class Foo{
    bar = 'bar'
    @msg par!:string
    @rec
    setBar(val:string){
        this.bar = val
    }
}
const foo = new Foo()
foo.log()//bar
foo.setBar("aaa")
foo.log()//aaa
console.log(foo.par)//bbb
Logo

前往低代码交流专区

更多推荐