JS July 15, 2019

如何使用 vue + typescript 编写页面(1)

Words count 8.4k Reading time 8 mins. Read count 0

原文地址

起步

使用 vue-cli 创建项目

vue create demo ,demo就是创建项目的名称
提示选择预设,选择 Manually select features 回车确认
选择typescript vuex router babel css pre-processors,不使用linter,不选单元测试有需要另说
回车后按照需要选择合适的选项
选择完毕后回车等待资源准备

编码开始

熟悉几个vue的装饰器 vue-property-decorator

以下的装饰器的功能和原js编写的功能相同/相似,可以参照官方文档类比解读。

import { Vue, Component, Inject, Provide, Prop, Model, Watch, Emit, Mixins } from 'vue-property-decorator'

1. Vue 实际上就是 Vue 本身,继承vue相关属性和函数

class MyComponent extends Vue { }

2. @Component 声明成一个vue的组件实例,如果不使用,则不能得到一个vue组件

第一种方式,不需要定义额外内容:

@Component
class MyComponent extends Vue { }

第二种方式,定义相关内容:

@Component({
    /* 这里和js版本编写的 vue 组件内容相同,
     * 凡是不能在ts里面完成的都可以在这里完成 
     * 最终会被合并到一个实例中。
     * 在这里定义的内容,不会被语法器获取到,因此必须要同步在class中声明
     */
    data(){
        return { myname:"",age:18 }
    }
})
class MyComponent extends Vue {
    private myname:string;
    mounted(){
        this.myname;    
        this.age;// 语法器报错,当前类找不到age属性
    }
}

3.@Provide 向任意层级的子组件提供可访问的属性,默认为当前属性的名称,可以指定名称

@Component
class ParentComponent extends Vue { 
    @Provide() private info!:string;
    @Provide("next") private infoNext!:string;
}

4. @Inject 获取父级由Provide提供的属性,默认为当前属性的名称,可以指定名称,多个父级提供相同名称属性时,获取最近父级的名称属性

@Component
class MyComponent extends Vue { 
    @Inject() private info!:string;
    @Inject("next") private infoNext!:string;
}

5. @Prop 由标签属性注入,获取对应标签属性上值,可配置具体prop内容,参照js版本props内容

@Component
class MyComponent extends Vue { 
   @Prop() age!:number;
   @Prop({default:1}) sex!:number;
}
<template>
    <MyComponent :age="16" />
</template>

<script lang="ts">  
import MyComponent from './MyComponent.vue';

@Component({
    components:{ MyComponent }
})
class PComponent extends Vue { }
</script>

6. @Model 是v-model的装饰器,当自定义组件想使用v-model时,可以使用这种方式,配合emit可以双向传递属性值

<template>
    <input type="checkbox" :checked="checked" @change="changed"/>
</template>

<script lang="ts">
@Component
class MyComponent extends Vue { 
   @Model("change") checked!:number;
   changed(event:any){ /* 这里是偷懒写的any,在实际项目中需要避免 */
       this.$emit("change",event.target.value)
   }
}
</script>
<template>
    <MyComponent :age="16" v-model="mycheck" />
</template>

<script lang="ts"> 
import MyComponent from './MyComponent.vue';

@Component({
    components:{ MyComponent }
})
class PComponent extends Vue {
    private mycheck:boolean = false;
}
</script>

7. @Watch 观察某个属性更新

@Component
class MyComponent extends Vue { 
   @Prop() age!:number;
   @Watch("age")
   ageChange(newVal:number,oldVal:number){
       /*age属性更新时,处理相关内容*/
   }
}

8. @Emit this.$emit 的装饰器,如果没有指定名称,默认使用函数名称。有返回值时,使用返回值,没有则使用

@Component
class MyComponent extends Vue { 
   private myname = "";
   
   @Emit()
   ageChangeA(){ /* 仅发送 this.$emit('ageChangeA') */   }
   
   @Emit()
   ageChangeB(age:number){ /* 发送 age  this.$emit('ageChangeB',age) */   }
   
   @Emit()
   ageChangeC(age:number){  return 1 /* this.$emit('ageChangeC',1) 发送return 结果*/ }
}

9. Mixins

// MyMixin.ts
@Component
export default class MyMixin extends Vue { 
   /* 如果使用private 修饰,则两个相同的 私有属性混入时,会产生冲突 */
   protected myname = "张三";
   created(){  /* 混入对象有自己的 生命周期函数*/ }
   getMyName(){ console.log("张三混入") }
}
// OtherMixin.ts
@Component
export default class OtherMixin extends Vue { 
   /* 如果使用private 修饰,则两个相同的 私有属性混入时,会产生冲突 */
   protected myname = "李四";
   created(){  /* 混入对象有自己的 生命周期函数*/ }
   getMyName(){ console.log("李四混入") }
}
@Component
class MyComponent extends Mixins(MyMixin,OtherMixin) { 
   private myname = ""; /* 混入对象已经定义,这里产生属性冲突 */
   mounted(){
       this.getMyName() // 李四混入
   }
}

对于computed,使用 get 替代

@Component
class MyComponent extends Vue { 
   private myname = ""; /* 混入对象已经定义,这里产生属性冲突 */
   get upperName(){
       return "A" + this.myname
   }
}

装饰器可以参照 vue-property-decorator

  • 没有filters,没有指令相关装饰器,有需要可以在@Component里面补充,或者可以直接定义函数调用计算返回值 在class里定义的属性即data属性,需要赋值初始值。

typescript 混用js

当我们引用了一个js编写的模块时会报错,这时候,如果不在引入的index文件里面添加.d.ts描述文件,那么这个模块就没法在语义上一致通过.

通用兼容性解决方案

如果这个模块是由npm下载的,并且有@types版本,可以直接使用npm install @types/xx下载

可惜,大部分都是没有编写声明文件的.但是又需要使用到这个模块时,应该怎么做.

自定义描述文件

在项目的【根目录】下定义【模块相同的名称】的描述文件A.d.ts,在描述文件内编写模块声明描述

// A.d.ts
declare module '*';

这样属于一劳永逸的描述,但是无法描述到具体模块内容,因此这种方式仅仅引入的组件没有任何操作时,比如引入的是第三方开发的vue组件,可以用这种方式偷懒.

详细描述文件

// A.d.ts
declare module  "A" {
    // 添加具体的描述内容
};

可以从这里查询到@type包查询,已经被编写的文件声明可以直接下载

0%