TypeScript在Vue项目中使用

Jul 17, 2020

前言

近两年来,TypeScript 的发展势头很猛。其实Vue官方从2.6.X版本开始就部分使用TypeScript重写了。而且根据 Evan You 发布的 Vue 3.0 计划,Vue 3.0 将完全使用 TypeScript 重写。说白了TypeScript还是很有前景的,那么作为一名热爱学习的程序员上手撸它就对了。

哎呀妈,真香。。。

TypeScript 是什么

TypeScript = Type + Script(标准JS)。我们从TS的官方网站上就能看到定义:TypeScript is a typed superset of JavaScript that compiles to plain JavaScript。TypeScript是JavaScript类型超集,他可以编译成纯的JavaScript。

最初,JavaScript 是一个为了浏览器而设计的语言,可以提供一些基础的用户交互。JS本身作为一个弱类型语言,在开发过程中有极大的灵活性,可能也正是这种灵活性,使得更多的开发人员接受这个在创始之初不被看好的语言。

随着最近几年,JavaScript的飞速发展。nodejs的出现,使得JS不在局限于浏览器中。而且随着单页面应用的流行,使得前端逐渐迈向工程化,项目也越来越庞大。那随之而来的问题就是松散的代码、乱七八糟的类型使的项目的越来越难以维护、被人写的代码难以难以读懂、稳定性差等问题也随之暴露出来。

TypeScript 有什么用?

  • TypeScript使代码更容易阅读和理解,有了类型系统的规范,每个方法的入参反参都会有一定的约束,正是这些约束使得代码更加容易阅读和理解。
  • 可维护性更好,长期迭代维护的项目开发和维护的成员会有很多,团队成员水平会有差异,在长期维护的过程中代码质量会慢慢降低,在强类型约束和静态检查,以及智能IDE的帮助下,提升可维护性。
  • TypeScript是类型系统,而且是JavaScript的超集。JavaScript能做的TypeScript都可以做,JavaScript做不到的TypeScript也可以做到。
  • TypeScript已经相对成熟了,网上的资料也很齐全,大部分的库和框架都对TypeScript做了很好支持
  • VSCode、WS等IDE对TypeScript的支持相当好,有智能提示,有智能感知bug。
  • 静态类型检查可以让我们的bug尽可能消灭在编译器,加上现代IDE有智能纠错,编码时就能提前感知bug的存在。

Vue组件的Ts写法

从零搭建一个Ts-vue项目

  1. 安装官方脚手架
npm install -g @vue/cli
# OR
yarn global add @vue/cli
  1. 执行创建项目的命令
vue create map-ts
  1. 选择配置项
    然后,命令行会要求选择预设。使用箭头键选择Manually select features。
    接下来就是你想要的配置了,当然如果创建的是ts项目的话TypeScript和Babel选项是必选的

-----

然后就是一步步选择你的配置项目了,我的是这个样子的,如下图

---2

接着等待项目初始化完成,就是下边这个样子的

--2

  1. 最后启动项目
yarn serve  
#or
npm run sercve

vue-property-decorator

这里单页面组件的书写采用的是 vue-property-decorator 库,该库完全依赖于 vue-class-component ,也是 vue 官方推荐的库。
单页面组件中,在 @Component({}) 里面写 props、data 等调用起来极其不方便,而 vue-property-decorator里面包含了 8 个装饰符则解决了此类问题,他们分别为:

@Emit 指定事件emit,可以使用此修饰符,也可以直接使用 this.$emit()
@Inject 指定依赖注入
@Mixins mixin 注入
@Model 指定 model
@Prop 指定 Prop
@Provide 指定 Provide
@Watch 指定 Watch
@Component export from vue-class-component

import { Component, Prop, Vue, Watch } from 'vue-property-decorator';

class Person {}

@Component
export default class Map extends Vue {
    mapData: string = ''
    count = 0;
    person: Person = {}

    // Prop 
    @Prop({default: 0}) private prop1 !: number;
    @Prop({ default: () => [10, 20, 30, 50] }) private prop2!: number[]

    // watcher
    @Watch('person', { immediate: true, deep: true })
    onPersonChanged (val: Person, oldVal: Person) {}
    
    // 生命周期
    private created ():void { },
    private mounted ():void { },
    private updated ():void { },
    private destroyed ():void { }
}

其他修饰符详情请参考vue-property-decorator这里就不一一列举了

一个Vue组件

下面是一个地图组件示例

<template>
<div>
    <h1 class="header">{{ reversedMessage }}</h1>
    <div class="map" id="mapContainer"></div>
</div>  
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import {getDataViz} from '@/api/dataViz'

@Component
export default class Map extends Vue {
    map: any;
    message = 'yeHoeG';
    // 计算属性(虽然没有必要,但是我想用一下)
	private get reversedMessage (){
        return this.message.split('').reverse().join('')
    }
    private async mounted () {
        // 初始化地图
        this.initMap()
        // 显示底图
        this.addTileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
            cluster: ['a', 'b', 'c']
        })
        // 发送可视化请求
        const vizId = await this.dataViz();
        // 加载瓦片
        this.addTileLayer(`http://geohey.com/s/dataviz/${vizId}/{z}/{x}/{y}.png?retina={i}&ak=MWRiZjhkYjRhNmNjNGZmYThiNzQzYjU0MWQ1MjE4YWM`, {
            crossOrigin: ''
        })
    }
    // 初始化地图
    initMap() {
        this.map = new this.$G.Map('mapContainer', {
            maxRes: 19567.879241,
            recordStatus: false,
            pinchRotate: false,
            continuouslyZoom: false,
            zoomDelta: 1,
            hideLogo: true,
            initStatus: {
                pitch: 10,
                center:[11791655.063735005, 4563584.047148498],
                res: 4891.96981025
            }
        });
    }
    // 获取dataViz
    async dataViz(): Promise<string> {
        let result: any;
        try {
            result = await getDataViz();
        } catch (err) {
            console.error(err)
        }
        if(result && result.code !== 0) {
            console.error(result)
        }
        return result.data.vizId
    }
    // 添加 瓦片图层
    addTileLayer(url: string, data: any) {
        const tileLayer = new this.$G.Layer.Tile(url, {
            ...data
        });
        tileLayer.addTo(this.map);
    }
}
</script>

结果如下图:

map-template

哈哈,一个TS-Vue组件就是这么简单

总结

在刚开始用TS写组件的时候,真的是特别不适应,被它的类型检查搞得有点烦躁,但是慢慢的一个组件写下来之后,发现TS的类型检查在编译的时候就帮我避免了很多bug。

在有JS的基础下,TS的学习成本不高,但是TS和一些框架一起使用的时候还是或多或少的有一些坑存在的。

没有最好的,只有最适合自己的,到底用不用TS,还是要看实际项目规模、项目生命周期、团队规模、团队成员情况等实际情况综合考虑。

评论正在加载...
Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.
分享