# Typescript 改造

# 组件

# 使用 Options 方式(不推荐)





 































<template>
  ...
</template>

<script lang="ts">
  import Vue, { PropOptions } from "vue";

  interface User {
    firstName: string;
    lastName: number;
  }

  export default Vue.extend({
    name: "YourComponent",

    props: {
      user: {
        type: Object,
        required: true,
      } as PropOptions<User>,
    },

    data() {
      return {
        message: "This is a message",
      };
    },

    computed: {
      fullName(): string {
        return `${this.user.firstName} ${this.user.lastName}`;
      },
    },
  });
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# 使用 Class 方式(推荐)

安装vue-class-component (opens new window)或者vue-property-decorator (opens new window)

TIP

vue-class-component (opens new window)由 Vue 官方维护,vue-property-decorator (opens new window)是社区根据vue-class-componentcreateDecorator创建出@Prop@Emit@Watch等等饰器方法的衍生插件。个人比较推荐vue-property-decorator

如果使用vue-class-component,格式如下:

<template>
  <div>
    <Avatar></Avatar>
    <span>{{ age | toAgeString }}</span>
  </div>
</template>

<script>
  import { Component, Mixins } from 'vue-class-component'
  import Avatar from './Avatar.vue'
  import ViewMixin from './mixin/view'

  @Component({
      model: {
          prop: 'name',
          event: 'change'
      },
      props: {
          name: String,
          email: String
      },
      filters: {
          toAgeString(age: number) {
              return 'my age:' + this.age.toString()
          }
      },
      components: {
          Avatar
      },
      watch: {
          age(newV: number, oldV: number) {

          }
      }
  })
  // export default class UserView extends Vue {
  export default class UserView extends Mixins(ViewMixin) {
      name!: string

      // data
      age = 18

      // mounted 生命周期
      mounted () {}

      // 计算属性
      get computedInfo () {
          return 'my name:' + this.name
      }

      // method
      handleClick () {
          this.$emit('change', this.computedInfo)
      }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

如果使用vue-property-decorator,格式如下:

<template>
  <div>
    <Avatar></Avatar>
    <span>{{ age | toAgeString }}</span>
  </div>
</template>

<script>
  import { Mixins, Component, Model, Prop, Watch, Emit } from 'vue-property-decorator'
  import Avatar from './Avatar.vue'
  import ViewMixin from './mixin/view'

  @Component({
      model: {
          prop: 'name',
          event: 'change'
      },
      props: {
          name: String
      },
      filters: {
          toAgeString(age: number) {
              return 'my age:' + this.age.toString()
          }
      },
      components: {
          Avatar
      },
      watch: {
          age(newV: number, oldV: number) {

          }
      }
  })
  export default class UserView extends Mixins(ViewMixin) {
      // v-model
      @Model('change', { type: String }) readonly name!: string

      // prop
      @Prop({ type: String, default: '' }) readonly email!: string

      // data
      age = 18

      // mounted 生命周期
      mounted () {}

      // 计算属性
      get computedInfo () {
          return 'my name:' + this.name
      }

      @Watch('age')
      ageChanged(newV: number, oldV: number) {

      }

      @Emit('change')
      handleClick () {
          return this.computedInfo
      }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

./mixin/view.ts

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

@Component
export default class ViewMixin extends Vue {
  // 和上面两个例子格式一致
}
1
2
3
4
5
6

# 中间件(Middlewares)

import { Middleware } from "@nuxt/types";

const myMiddleware: Middleware = (context) => {
  // Use context
};

export default myMiddleware;
1
2
3
4
5
6
7

# 插件(Plugins)

# 注入 Vue 实例

# 注入

function myInjected(this: Vue, message: string) {
  console.log(this.name + message);
}

Vue.prototype.$myInjectedFunction = myInjected;

declare module "vue/types/vue" {
  interface Vue {
    $myInjectedFunction: typeof myInjected;
  }
}
1
2
3
4
5
6
7
8
9
10
11

# 使用

<template>
  <div>
    <button @click="$myInjectedFunction()">Click me !</button>
    <button @click="someMethod">Click me !</button>
  </div>
</template>

<script lang="ts">
  import Vue from "vue";

  export default Vue.extend({
    mounted() {
      this.$myInjectedFunction("works in mounted");
    },
  });
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 注入 Nuxt 实例(context)

# 注入

import { Plugin } from "@nuxt/types";

const myPlugin: Plugin = (context) => {
  context.$myInjectedFunction = (message: string) => console.log(message);
};

export default myPlugin;

declare module "@nuxt/types" {
  interface Context {
    $myInjectedFunction(message: string): void;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 使用

<script lang="ts">
  import { Vue, Component } from "vue-property-decorator";

  @Component({
    asyncData(context) {
      context.$myInjectedFunction("works in asyncData");
    },
  })
  export default class Home extends Vue {}
</script>
1
2
3
4
5
6
7
8
9
10

# 同时注入

# 注入

import { Plugin } from "@nuxt/types";

const myPlugin: Plugin = (context, inject) => {
  inject("myInjectedFunction", (message: string) => console.log(message));
};

export default myPlugin;

declare module "vue/types/vue" {
  interface Vue {
    $myInjectedFunction(message: string): void;
  }
}

declare module "@nuxt/types" {
  interface NuxtAppOptions {
    $myInjectedFunction(message: string): void;
  }
}

declare module "vuex/types/index" {
  interface Store<S> {
    $myInjectedFunction(message: string): void;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 使用

<script lang="ts">
  import { Vue, Component } from "vue-property-decorator";

  @Component({
    asyncData(context) {
      context.$myInjectedFunction("works in asyncData");
    },
  })
  export default class Home extends Vue {
    mounted() {
      this.$myInjectedFunction("works in mounted");
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

TIP

未完,待续...