zoukankan      html  css  js  c++  java
  • 使用 typescript ,提升 vue 项目的开发体验(1)

    此文已由作者张汉锐授权网易云社区发布。

    欢迎访问网易云社区,了解更多网易技术产品运营经验。


    前言:对于我们而言,typescript 更像一个工具


    官方指南

    从 vue2.5 之后,vue 对 ts 有更好的支持。根据官方文档,vue 结合 typescript ,有两种书写方式:


    Vue.extend

      import Vue from 'vue'
    
      const Component = Vue.extend({    // type inference enabled
      })


    Class-style Vue Components

      import Vue from 'vue'
      import Component from 'vue-class-component'
    
      // The @Component decorator indicates the class is a Vue component
      @Component({    // All component options are allowed in here
        template: '<button @click="onClick">Click!</button>'
      })
      export default class MyComponent extends Vue {    // Initial data can be declared as instance properties
        message: string = 'Hello!'
    
        // Component methods can be declared as instance methods
        onClick (): void {      window.alert(this.message)
        }
      }


    理想情况下,Vue.extend 的书写方式,是学习成本最低的。在现有写法的基础上,几乎 0 成本的迁移

    // 现在常见的写法export default {    // your code }


    但「理想丰满,现实骨感」,问题出在:


    • Vue.exend 在和 vuex 和 mixins 结合使用的时候,无法发挥 ts 的作用,vuex 和 mixins 会在项目中大量使用,这个问题不能忽视。


    Vue.extend + vuex + mixins 问题的介绍


    Vue.extend + vuex 的问题

    由于 vuex 使用  mapState, mapActions 等方法的时候,通过字符串形式做映射,这个过程中,丢失了类型信息。下面的 gif 可以看到,整个过程中:

    • 无法做代码提示

    • 无法对对应的 actions  和 state 做类型声明,使得类型检查生效

    • 无法使用重构

      Alt pic


    显然,如果只有一部分的方法和属性得到了代码提示和类型检查,就是失去了使用 typescript 意义。

    在 Vue.extend + vuex 写法下,这个问题暂时没有解决方案。


    Vue.extend + mixins 的问题

    同样的问题,在 mixin 中定义的方法,不会被 typescript 识别到,下面 gif 可以看到,不仅仅「代码提示」「类型检查」「代码重构」没有工作,甚至因识别不到 test 而报错

    Alt pic


    Alt pic


    Class-Style Components


    那么就剩下 Class-Style Components 方案。当然,这个方案需要做额外的工作才能够让「vue 全家桶 + ts」良好的工作。

    原理:将属性直接挂载在 class 上,使得 typescript 能够良好的进行「代码提示」和「类型检查」。然后再通过装饰器将属性转成 vue 上的属性。


    例如 @Prop, @Watch, @Action 等装饰器,将属性做相应的转换成 props,  watch, mapActions 里面的值,具体后面例子展示。


    vue-class-component


    这里库提供最基础的 vue 装饰器:@Component 。其他的 vue 装饰器库,都在这个库的基础上做扩展和修改。看看官网的例子:


    import Vue from 'vue'import Component from 'vue-class-component'// @Component 会将 MyComponent 中的属性,转换成 vue 对应的属性@Component({  // Vue 所有的属性都可以在这里声明,一般用到的比较少
      template: '<button @click="onClick">Click!</button>'})
    export default class MyComponent extends Vue {  // @Component 将 message 转成成 data 
      message: string = 'Hello!'
    
      // @Component 会将这里的 getter 属性,转换成 computed
      get name(){    return 'anders'
      }  // @Component 识别到 created 是声明周期关键字,不做处理
      created(){}  // @Component 识别到 onClick 不是关键字,将它转成 methods  
      onClick (): void {    window.alert(this.message)
      }
    }


    vue-property-decorator


    这个库提供了:


    • @Emit

    • @Inject

    • @Model

    • @Prop

    • @Provide

    • @Watch


    其中常用的: @Prop,@Watch,@Emit。 看例子:


    import { Component, Emit, Inject, Model, Prop, Provide, Vue, Watch } from 'vue-property-decorator'const s = Symbol('baz')
    
    @Component
    export class MyComponent extends Vue {
    
      @Emit()
      addToCount(n: number){ this.count += n }
    
      @Emit('reset')
      resetCount(){ this.count = 0 }
    
      @Prop()
      propA: number
    
      @Prop({ default: 'default value' })
      propB: string
    
      @Prop([String, Boolean])
      propC: string | boolean
    
      @Watch('child')
      onChildChanged(val: string, oldVal: string) { }
    
      @Watch('person', { immediate: true, deep: true })
      onPersonChanged(val: Person, oldVal: Person) { }
    }


    上面的使用就相当于:


    const s = Symbol('baz')
    
    export const MyComponent = Vue.extend({
      name: 'MyComponent',
    
      props: {
        checked: Boolean,
        propA: Number,
        propB: {
          type: String,      default: 'default value'
        },
        propC: [String, Boolean],
      },
    
    
      methods: {
        addToCount(n){      this.count += n      this.$emit("add-to-count", n)
        },
        resetCount(){      this.count = 0
          this.$emit("reset")
        },
        onChildChanged(val, oldVal) { },
        onPersonChanged(val, oldVal) { }
      },
      watch: {    'child': {
          handler: 'onChildChanged',
          immediate: false,
          deep: false
        },    'person': {
          handler: 'onPersonChanged',
          immediate: true,
          deep: true
        }
      }
    })


    更加全面的用法参考文档:vue-property-decorator


    免费体验云安全(易盾)内容安全、验证码等服务

    更多网易技术、产品、运营经验分享请点击


    相关文章:
    【推荐】 iOS安装包瘦身(上篇)

  • 相关阅读:
    D3.js 几种常用的坐标轴
    前端页面的用户体验优化设计
    用can-fixture拦截Ajax并模拟响应
    webpack入门及使用
    CommonJS和AMD规范
    凝思6.0虚拟机搭建--遇到的问题
    凝思6.0安装vmware tools记录
    linux定时任务crontab命令
    find命令使用指南
    关于字体、字形、字符集、字体大小
  • 原文地址:https://www.cnblogs.com/zyfd/p/9907925.html
Copyright © 2011-2022 走看看