在vue中使用typescript - 使用篇

基本使用

// page页面======================================================================
import { Component, Vue } from 'vue-property-decorator'
import NavBar from '@/components/NavBar.vue'
// 使用组件
@Component({
  components: {
    NavBar
  }
})
// 创建页面组件
export default class App extends Vue {
  
}

// 接口interface 文件=============================================================
export interface MainButtonType {
  id: number;
  icon: string | any;
  name: string
}


// 组件===========================================================================
<template>
  <div class="home">
    <swiper :options="swiperOption" class="swiper-wrap">
      <swiper-slide v-for="(slide, index) in swiperData" :key="index">
        <img :src="slide.imgUrl" />
      </swiper-slide>
      <div class="swiper-pagination" slot="pagination"></div>
    </swiper>

    <div class="button-wrap">
      <main-button :ButtonData="ButtonData" @buttonClick="handleButtonClick"/>
    </div>

    <div class="exp">
      <filter-component/>
    </div>
  </div>
</template>

import 'swiper/dist/css/swiper.css'
import { swiper, swiperSlide } from 'vue-awesome-swiper'
import { Component, Prop, Vue } from 'vue-property-decorator'
import MainButton from '@/components/MainButton.vue'
import FilterComponent from '@/components/FilterComponent.vue'
import { MainButtonType } from '@/types'

@Component({
  components: {
    swiper,
    swiperSlide,
    MainButton,
    FilterComponent
  }
})
export default class Home extends Vue {
  // 定义data数据
  private swiperData: any[] = [
    {
      id: 0,
      imgUrl: require('../assets/banner.png')
    }
  ]
  private swiperOption: object = {}
  // 使用interface接口定义类型 => MainButtonType
  private ButtonData: MainButtonType[] = [
    {
      id: 0,
      icon: require('../assets/travel_application.png'),
      name: '出差申请'
    },
    {
      id: 1,
      icon: require('../assets/flight.png'),
      name: '机票'
    }
  ]
  // 接口子组件的emit的函数
  private handleButtonClick(id: number): void {
    console.log('id:', id)
  }
}

// MainButton 组件中(子组件)===============================================================
import { Component, Prop, Vue, Emit, Watch } from 'vue-property-decorator'
import { MainButtonType } from '@/types'

@Component
export default class MainButton extends Vue {
  // props
  @Prop({default: []}) ButtonData!: MainButtonType[]
  // 生命周期
  created(): void {
    console.log('created')
  }
  // watch
  @Watch('ButtonData', {deep: true, immediate: true})
  ButtonDataWatch(val: MainButtonType[]):void {
    console.log(123, val)
  }
  // emit
  @Emit('buttonClick')
  private handleItemClick(id: number): void {
    // 函数的参数值即是emit的payload
  }
}

// filterComponent组件:filters和computed示例 (子组件)==================================================================
<template>
  <div class="filter-wrap">
    <div>filters示例:{{exp | formatNum}}</div>
    <br/>
    <div>computed示例:{{computedNum}}</div>
  </div>
</template>

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

@Component({
  // filters
  filters: {
    formatNum(val: number): string {
      if (!val && val !== 0) return ''
      return val.toFixed(2)
    }
  }
})
export default class FilterComponent extends Vue {
  private exp: number = 12.346546754
  // computed
  get computedNum(): number {
    return this.exp * 1000
  }
}

在vuex中使用

  1. 注: typescript目前对vuex的支持还不完善,需要引入 vuex-class 包来支持
  2. vuex-class 提供了State, Getter, Action, Mutation, nam-espace 这几个装饰器
  3. 示例
// vuex中, 以state为例
// 1. 定义接口
export interface USERINFO {
  userId: number;
  userName: string;
  avatar: string
}

export default interface STATE {
  userInfo: USERINFO;
}

// 2. state.js使用接口
import STATE from './stateType.js';
const state: STATE = {
  userInfo: {
    userId: 0,
    userName: '',
    avatar: '',
  }
};
export default state;


// 组件中使用
import Vue from 'vue'
import Component from 'vue-class-component'
import {
  State,
  Getter,
  Action,
  Mutation,
  namespace
} from 'vuex-class'

const someModule = namespace('path/to/module')

@Component
export class MyComp extends Vue {
  @State('foo') stateFoo
  @State(state => state.bar) stateBar
  @Getter('foo') getterFoo
  @Action('foo') actionFoo
  @Mutation('foo') mutationFoo
  @someModule.Getter('foo') moduleGetterFoo

  @State foo
  @Getter bar
  @Action baz
  @Mutation qux

  created () {
    this.stateFoo // -> store.state.foo
    this.stateBar // -> store.state.bar
    this.getterFoo // -> store.getters.foo
    this.actionFoo({ value: true }) // -> store.dispatch('foo', { value: true })
    this.mutationFoo({ value: true }) // -> store.commit('foo', { value: true })
    this.moduleGetterFoo // -> store.getters['path/to/module/foo']
  }
}

注意事项

  1. vue-property-decoratorvue-class-component 的区别
  • vue-class-component 是 vue 官方出的
  • vue-property-decorator 是社区出的
  • 其中vue-class-component 提供了 vue component 等等
  • vue-property-decorator 深度依赖了 vue-class-component 拓展出了很多操作符@Prop @Emit @Inject等等 可以说是vue-class-component的一个超集
  • 正常开发的时候 你只需要使用vue-property-decorator中提供的操作符即可 不用再从vue-class-componen引入vue component
  1. 引入第三方包报错
  • 现象: Could not find a declaration file for module 'vue-awesome-swiper'
    e7e1f5f462d88e9d304441f1e1cb962.png
  • 原因: 插件文件可能不是.ts文件而是.js文件
  • 解决方案一: 安装对应的ts模块
  • 解决方案二: 配置 shims-vue-d.ts 文件(推荐)
      import Vue from "vue"
      import VueRouter, { Route } from "vue-router"
    
      declare module '*.vue' {
        export default Vue
      }
    
      declare module "vue/types/vue" {
        interface Vue {
          $router: VueRouter; // 这表示this下有这个东西
          $route: Route;
          $https: any;
          $urls: any;
          $Message: any;
          $Modal: any;
        }
      }
      // 以swiper为例,在此添加声明
      declare module 'vue-awesome-swiper'
    
  • 解决方案三: 配置 tsconfig.json 文件
      {
        "compilerOptions": {
          ...
          "noImplicitAny": false,   // 忽略引入类型检查
          ......
        }
      }
    
  1. 声明全局变量
  • 添加shime-global.d.ts文件,与main.ts同级
// 声明全局的 window ,不然使用 window.XX 时会报错
// declare var window: Window;
declare var document: Document;
declare var THREE: any;

// interface THREE extends Window {}

// element-ui
declare module "element-ui/lib/transitions/collapse-transition";
declare module "element-ui";
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容