TypeScript-使用typescript构建vue应用

本文最后更新于:a few seconds ago

砍柴先磨刀 🎄

我们使用VSCode来进行编码,首先我们要安装TSLintTSLint Vue来规范和校验我们的编码。(代码质量第一位)
(这两个家伙会经常发生失灵的情况)

配置TSLint

  1. 打开 File->Preferences->Settings

  2. 搜索TSLint

  3. 打开Settings.json

  4. 将下面代码复制进去

        //setting.json
      { 
       "editor.codeActionsOnSave": {
            "source.fixAll.tslint": true
        },
      }
    
  5. 我是关闭vsCode然后再打开生效的。

创建类的Vue模板

  1. 点击File->Preferences->User Snippets

  2. 然后点击 New Snippets 新建文件 vuets-code-snippet.json.code-snippets

  1. 将下列模板复制进去

    //vuets-code-snippet.json.code-snippets
    {
    “Print to console”: {
    “prefix”: “vuets”,
    “body”: [
    “,
    “,

    ],
    “description”: “basic vue typescript template”
    }
    }

  2. 然后在.vue文件就可以打出vuetsTab 就可以生成模板啦。

使用vue-cli创建项目

选择typescript,其他按照需求来

  (*) Babel
  (*) TypeScript
  ( ) Progressive Web App (PWA) Support
  (*) Router
  (*) Vuex
  (*) CSS Pre-processors
  (*) Linter / Formatter
  ( ) Unit Testing
  ( ) E2E Testing

献上代码规范

直接复制下面代码粘贴到你的tslint.json就可以了,然后想深入了解可以看官方tslint.json设置篇

{
  "defaultSeverity": "warning",
  "extends": [
      "tslint:recommended"
  ],
  "linterOptions": {
      "exclude": [
          "node_modules/**"
      ]
  },
  "no-trailing-whitespace": false,
  "rules": {
      "quotemark": false,
      "indent": [true, "spaces", 4],
      "interface-name": false,
      "ordered-imports": false,
      "object-literal-sort-keys": false,
      "no-console": false,
      "no-debugger": false,
     
      "no-unused-expression": [true, "allow-fast-null-checks"], 
      "no-unused-variable": false, 
      "triple-equals": true,
      "no-parameter-reassignment": true,
      "no-conditional-assignment": true,
      "no-construct": true, 
      "no-duplicate-super": true, 
      "no-duplicate-switch-case": true,
      "no-object-literal-type-assertion": true, 
      "no-return-await": true, 
      "no-sparse-arrays": true, 
      "no-string-throw": true,
      "no-switch-case-fall-through": true, 
      "prefer-object-spread": true, 
      "radix": true, 
      "cyclomatic-complexity": [
          true,
          20
      ], 
      "deprecation": true, 
      "use-isnan": true, 
      "no-duplicate-imports": true, 
      "no-mergeable-namespace": true, 
      "encoding": true, 
      "import-spacing": true,
      "interface-over-type-literal": true,
      "new-parens": true,
      "no-angle-bracket-type-assertion": true, 
      "no-consecutive-blank-lines": [
          true,
          3
      ]  
    }
}

我们来实现todoItem

抽离接口文件

接口是可以导出的,我们将接口抽离出来
在src目录下新建types文件夹,新建todo.ts文件,内容如下

export interface ITodo {
    text: string;
    complete: boolean;
}

创建基础文件

我们可以先了解:Vue属性装饰器,让我们更快的编码。

@Prop
@PropSync
@Model
@Watch
@Provide
@Inject
@ProvideReactive
@InjectReactive
@Emit
@Ref
@Component(由 vue-class-component提供)
Mixins(mixins 由 vue-class-component 提供的名为helper的函数)

Home.vue应该像这样
/src/views/Home.vue
<template>
  <div>
    <ul>
      <li v-for="(item,index) in lists" :key="index">
        <TodoItem :item="item" :index="index" @say="say"></TodoItem>
      </li>
    </ul>
  </div>
</template>
<script lang='ts'>
import { Component, Vue } from "vue-property-decorator";
import TodoItem from "../components/TodoItem";
import { ITodo } from "../types/todo";

@Component({
  components: {
    TodoItem,
  },
})
export default class Home extends Vue {
  public lists: ITodo[] = [
    { text: "打代码" },
    { text: "睡觉" },
  ];

  get count() {
    return this.lists.length;
  }
  public say(): void {
    console.log("你在干啥");
  }
}
</script>
}

我们先来看一下@Component里面是什么东西

import Vue, { ComponentOptions } from 'vue';
import { VueClass } from './declarations';
export { createDecorator, VueDecorator, mixins } from './util';
declare function Component<V extends Vue>(options: ComponentOptions<V> & ThisType<V>): <VC extends VueClass<V>>(target: VC) => VC;
declare namespace Component {   //外部命名空间声明
    var registerHooks: (keys: string[]) => void;
}
declare function Component<VC extends VueClass<Vue>>(target: VC): VC;
declare namespace Component {
    var registerHooks: (keys: string[]) => void;
}
export default Component;  //这里我们看得懂

他给我们吐出了一个Component,所以他其实干了这样事

export default {
    component:{},
    props: {},
    watch: { }
}
在 /components里新建TodoItem.tsx

内容如下

    /components/TodoItem.tsx
 import { Component, Vue, Prop } from 'vue-property-decorator';
 import { ITodo } from '../types/todo';
 
 @Component
 export default class TodoItem extends Vue {
     @Prop(Object) public item !: ITodo;  //属性传递的方法
     @Prop(Number) public index !: number;
     public save() {
         this.$emit('say');
     }
     public render() {
         return <h1>{this.item.text}<button on-click={this.save}>触发方法</button></h1>;
     }
 }

让我们来认识一下这个语法糖

//原来的写法
props: {
    item: {
        type: ITodo,
        defalut: ''
    }
}

//语法糖的写法
@Prop(Object) public item !: ITodo;  //属性传递的方法

的意思是如果是空的,就不校验,代表这个值一定有。

@Emit语法糖

以上代码实现父向子传递数据,和子触发父方法。
但是这样写不够好看,官方给我们提供了一个更加美观的装饰器(Emit)。将TodoItem.tsx内容改写如下

/src/components/TodoItem.tsx
import { Component, Vue, Prop, Emit } from 'vue-property-decorator';
import { ITodo } from '../types/todo';

@Component
export default class TodoItem extends Vue {
    @Prop(Object) public item !: ITodo;
    @Prop(Number) public index !: number;
    @Emit('say') //我要触发的是父亲的方法
    public save() {
         return "hello";
    }
    public render() {
        return <h1>{this.item.text}<button on-click={this.save}>触发方法</button></h1>;
    }
}

@Emit('say')传入的是父亲的方法,但是如果父亲的方法和要装饰的方法名称相同,里面的内容可以不传 @Emit()

那传参怎么传呢? 我们现在已经return出了一个hello,现在只需要改写一下父亲的方法

public say(msg: string): void {
    console.log(msg);
  }

这样就能接收到数据。

实现点击加1的操作

/src/components/TodoItem.tsx
import { Component, Vue, Prop, Emit } from 'vue-property-decorator';
import { ITodo } from '../types/todo';

@Component
export default class TodoItem extends Vue {
    public count: number = 1;  //声明常量方法
    @Prop(Object) public item !: ITodo;
    @Prop(Number) public index !: number;
    @Emit('say')
    public save() {
       return "hello";
    }
    public increment() {
        this.count += 1;
    }
    public render() {
        return <h1>{this.item.text}<button on-click={this.save}>触发方法</button>
        {this.count}
        <button on-click={this.increment}>点击加一</button>
        </h1>;
    }
}
现在我想监控count变化

Watch装饰器可以满足我们的要求,但是它只能监控方法,或类。

/src/components/TodoItem.tsx
import { Component, Vue, Prop, Emit, Watch } from 'vue-property-decorator';
import { ITodo } from '../types/todo';

@Component
export default class TodoItem extends Vue {
    public count: number = 1;
    @Prop(Object) public item !: ITodo;
    @Prop(Number) public index !: number;
    @Emit('say')
    public save() {
       return "hello";
    }

    @Watch('count') //监控
    public fn(){
        console.log("count加1了");
    }

    public increment() {
        this.count += 1;
    }
    public render() {
        return <h1>{this.item.text}<button on-click={this.save}>触发方法</button>
        {this.count}
        <button on-click={this.increment}>点击加一</button>
        </h1>;
    }
}

加上vuex

我们首先改写我们的Home.vue

该写完应该像下面这样

/src/views/Home.vue
<template>
  <div>
    <ul>
      <li v-for="(item,index) in lists" :key="index">
        <TodoItem :item="item" :index="index" @say="say"></TodoItem>
      </li>
    </ul>
    {{this.lists}}
  </div>
</template>
<script lang='ts'>
import { Component, Vue } from "vue-property-decorator";
import TodoItem from "../components/TodoItem";
import { ITodo } from "../types/todo";
import { State, Mutation, Action } from "vuex-class"; //引入

@Component({
  components: {
    TodoItem,
  },
})
export default class Home extends Vue {
  @State("lists") public lists!: [];  //@State
  get count() {
    return this.lists.length;
  }
  
 @Mutation("hello") public say!: () => void; //触发mutation里的方法
  private mounted() {
    this.say();
  }
  //   public say(msg: string): void {
  //     console.log(msg);
  //   }
}
</script>
编写/store/index.ts 文件
/src/store/index.ts
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);
// tslint:disable-next-line: no-duplicate-imports
import { ITodo } from '../types/todo';

interface IList {
  lists: ITodo[];
}

export default new Vuex.Store< IList>({
  state: {
    lists: [
      {text: '吃饭', complete: true},
      {text: '打代码', complete: false},
    ],
  },
  mutations: {
    hello() {
      console.log(1);
    },
  },
  actions: {
  },
  modules: {
  },
});

结束🐟

芙蓉湖上芙蓉花,秋风未落如朝霞。「送荪友」——纳兰性德


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!