Как написать приложение Vue с помощью TypeScript

внешний интерфейс
Как написать приложение Vue с помощью TypeScript

предисловие

Уже 2020 год, а я еще не начал использовать ts в проекте, пользуюсь паникой дома, чтобы попробовать ts в первый раз. Ниже я покажу, как создать приложение Vue + TypeScript с помощью Vue CLI.

Инициализировать проект

Vue create ts-vue

выберитеManually select featuresЗдесь я выбрал Babel, TypeScript, Router, Vuex, препроцессоры CSS, Linter/Formatter.WechatIMG84.pngЗатем следуйте инструкциям по установке, окончательная конфигурация выглядит следующим образом.2.pngПосле установки следуйте подсказкам

cd ts-vue
npm run serve

Откройте адрес в браузере"http://localhost:8080/", вы можете видеть, что проект запущен

Структура проекта

├── public
│   ├── favicon.ico
│   └── index.html
├── src
│   ├── assets
│   │   └── logo.png
│   ├── components
│   │   └── HelloWorld.vue
│   └── views
│       ├── About.vue
│       └── Home.vue
│   ├── App.vue
│   ├── main.ts
│   ├── router.ts
│   ├── shims-tsx.d.ts
│   ├── shims-vue.d.ts
│   ├── store.ts
├── eslintrc.js
├── babel.config.js
├── package-lock.json
├── package.json
├── README.md
└── tsconfig.json

shims-tsx.d.ts: позволяет использовать файлы .tsx в проектах vue.

shims-vue.d.ts: позволяет импортировать и использовать отдельные файловые компоненты .vue, поскольку typescript по умолчанию не поддерживает импорт файлов vue.

В этой статье в основном рассказывается, как использовать TypeScript для написания из следующих пяти аспектов.

  1. Class-based components
  2. Data, props, computed properties, methods, watchers, and emit
  3. Lifecycle hooks
  4. Mixins
  5. Vuex

1.Class-based components

// ts
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
@Component
export default class HelloWorld extends Vue {
}
</script>

Код js, эквивалентный ts:

<script>
export default {
  name: 'HelloWorld'
}
</script>

Чтобы использовать TypeScript, вам нужно добавить тег скриптаlang = ts

vue-property-decorator — это сторонний пакет, который берет официальный пакет vue-class-component и добавляет к нему больше декораторов. Мы также можем использовать атрибут name для имени компонента, но достаточно использовать его как имя класса.

vue-property-decorator

@component({
  name: 'HelloWorld'
})

2. Импорт компонентов Способ введения других компонентов в компонент следующий:

<template>
  <div class="main">
    <User />
  </div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import User from '@/components/User.vue'
@Component({
  components: {
    User
  }
})
export default class HelloWorld extends Vue {
}
</script>

Код js, эквивалентный ts:

<template>
  <div class="main">
    <User />
  </div>
</template>
<script>
import User from '@/components/User.vue'
export default {
  name: 'HelloWorld',
  components: {
    User
  }
})
</script>

2. Data, props, computed properties, methods, watchers

использовать данные
@Component
export default class HelloWorld extends Vue {
  private msg: string = "welcome to my app"
  private list: Array<object> = [
    {
        name: 'Melody',
        age: '20'
    },
    {
        name: 'James',
        age: '20'
    }
  ]
}

js-код, эквивалентный ts

export default {
  data() {
    return {
      msg: "welcome to my app",
      list: [
        {
          name: 'Melody',
          age: '20'
        },
        {
          name: 'James',
          age: '20'
        }
      ]
    }
}
использовать реквизит

Вы можете добавить обязательный тип по умолчанию, чтобы указать требования проверки для реквизита, а также вы можете использовать только чтение, чтобы запретить работу реквизита.

import { Component, Prop, Vue } from 'vue-property-decorator'
@Component
export default class HelloWorld extends Vue {
  @Prop() readonly msg!: string
  @Prop({default: 'Joy Melody'}) readonly name: string
  @Prop({required: true}) readonly age: number,
   @Prop(String) readonly address: string
  @Prop({required: false, type: String, default: 'Developer'}) readonly job: string
}
</script>

Код js, эквивалентный ts, выглядит следующим образом

export default {
  props: {
    msg,
    name: {
      default: 'Joy Melody'
    },
    age: {
      required: true,
    },
    address: {
      type: String
    },
    job: {
      required: false,
      type: string,
      default: 'Developer'
    }
  }
}

Вычисляемое свойство

Вычисляемые свойства обычно используются для написания простой логики шаблона.

export default class HelloWorld extends Vue {
  get fullName(): string {
    return this.first+ ' '+ this.last
  }
}

Код js, эквивалентный ts, выглядит следующим образом

export default {
  fullName() {
    return this.first + ' ' + this.last
  }
}

Когда вам нужно написать немного более сложный код с использованием сеттеров и геттеров Когда используется вычисляемое свойство, оно записывается в ts следующим образом

export default class HelloWorld extends Vue {
  get fullName(): string {
    return this.first+ ' '+ this.last
  }
  set fullName(newValue: string) {
    let names = newValue.split(' ')
    this.first = names[0]
    this.last = names[names.length - 1]
  }
}

js, эквивалентный ts, записывается следующим образом

fullName: {
  get: function () {
    return this.first + ' ' + this.last
  },
  set: function (newValue) {
    let names = newValue.split(' ')
    this.first = names[0]
    this.last = names[names.length - 1]
  }
}
Watch

@Watch(path: string, options: WatchOptions = {})

  • Декоратор @Watch принимает два параметра: path: string Имя отслеживаемого свойства.
  • options?: WatchOptions={} options может содержать два свойства
    • немедленно?: логическое значение, следует ли вызывать функцию обратного вызова сразу после начала прослушивания
    • deep?:boolean Следует ли вызывать эту функцию обратного вызова при изменении свойства прослушиваемого объекта
@Watch('child')
onChildChanged (val: string, oldVal: string) {
    if (val !== oldVal) {
      window.console.log(val)
    }
}

Код js, эквивалентный ts, выглядит следующим образом

watch: {
    'child': {
        handler: 'onChildChanged',
        immediate: false,
        deep: false 
    }
},
method: {
    onChildChanged(val, oldVal) {
        if (val !== oldVal) {
          window.console.log(val)
        }
    }
}

Его также можно записать как: @Watch('child', {immediate: true, deep: true}), что эквивалентно:

watch: {
    'child': {
        handler: 'onChildChanged',
        immediate: true,
        deep: true 
    }
},
method: {
    onChildChanged(val, oldVal) {
        if (val !== oldVal) {
          window.console.log(val)
        }
    }
}

Methods
export default class HelloWorld extends Vue {
  public clickMe(): void {
    console.log('clicked')
    console.log(this.addNum(4, 2))
  }
  public addNum(num1: number, num2: number): number {
    return num1 + num2
  }
}

Код js, эквивалентный ts, выглядит следующим образом

export default {
  methods: {
    clickMe() {
      console.log('clicked')
      console.log(this.addNum(4, 2))
    }
    addNum(num1, num2) {
      return num1 + num2
    }
  }
}
Emit

Дочерний компонент запускает пользовательское событие родительского компонента и передает данные с помощью декоратора @Emit в TypeScript.

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

@Component
export default class YourComponent extends Vue {
  count = 0

  @Emit()
  addToCount(n: number) {
    this.count += n
  }

  @Emit('reset')
  resetCount() {
    this.count = 0
  }

  @Emit()
  returnValue() {
    return 10
  }

  @Emit()
  onInputChange(e) {
    return e.target.value
  }

  @Emit()
  promise() {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve(20)
      }, 0)
    })
  }
}

Код js, эквивалентный ts, выглядит следующим образом

export default {
  data() {
    return {
      count: 0
    }
  },
  methods: {
    addToCount(n) {
      this.count += n
      this.$emit('add-to-count', n)
    },
    resetCount() {
      this.count = 0
      this.$emit('reset')
    },
    returnValue() {
      this.$emit('return-value', 10)
    },
    onInputChange(e) {
      this.$emit('on-input-change', e.target.value, e)
    },
    promise() {
      const promise = new Promise(resolve => {
        setTimeout(() => {
          resolve(20)
        }, 0)
      })

      promise.then(value => {
        this.$emit('promise', value)
      })
    }
  }
}

3.Lifecycle hooks

Поскольку хуки жизненного цикла вызываются автоматически, они не принимают ни параметров, ни возвращают никаких данных, поэтому модификаторы доступа не требуются. Входной параметр или возвращаемый тип

export default class HelloWorld extends Vue {
  mounted() {
    //do something
  }
  beforeUpdate() {
    // do something
  }
}

js-код, эквивалентный ts

export default {
  mounted() {
    //do something
  }
  beforeUpdate() {
    // do something
  }
}

4.Mixins

Предполагая, что в настоящее время существует файл mixins/ProjectMixin Как использовать его в других компонентах следующим образом

<template>
  <div class="project-detail">
    {{ projectDetail }}
  </div>
</template>
<script lang="ts">
import { Component, Vue, Mixins } from 'vue-property-decorator'
import ProjectMixin from '@/mixins/ProjectMixin'
@Component
export default class Project extends Mixins(ProjectMixin) {
  get projectDetail(): string {
    return this.projName + ' ' + 'HS'
  }
}
</script>

Код js, эквивалентный ts, выглядит следующим образом

<template>
  <div class="project-detail">
    {{ projectDetail }}
  </div>
</template>
<script>
import ProjectMixin from '@/mixins/ProjectMixin'
export default {
  mixins: [ ProjectMixin ],
  computed: {
    projectDetail() {
      return this.projName + ' ' + 'HS'
    }
  }
}
</script>

5.vuex

Прежде чем читать этот раздел, уясните, что такоепространство имен vuex

Установить первым

npm install vuex-module-decorators -D
npm install vuex-class -D

Если вы хотите использовать модуль в виде пространства имен, вам нужно добавить дополнительные параметры в декоратор @Module.Например, следующий пример кода добавляет модуль с пользователем в пространстве имен

import { VuexModule, Module, Mutation, Action } from 'vuex-module-decorators'
@Module({ namespaced: true, name: 'user' })
class User extends VuexModule {
  public name: string = ''
  @Mutation
  public setName(newName: string): void {
    this.name = newName
  }
  @Action
  public updateName(newName: string): void {
    this.context.commit('setName', newName)
  }
}
export default User
Уведомление

Значение имени поля атрибута декоратора @Module должно совпадать с именем зарегистрированного имени модуля в новом хранилище ({modules: {}}). js-код, эквивалентный ts

export default {
  namespaced: true,
  state: {
    name: ''
  },
  mutations: {
    setName(state, newName) {
      state.name = newName
    }
  },
  actions: {
    updateName(context, newName) {
      context.commit('setName', newName)
    }
  }
}

Использовать vuex в компонентах

Чтобы использовать Vuex, вы можете использоватьvuex-classбиблиотека. Эта библиотека предоставляет декораторы для привязки компонентов State, Getter, Mutation и Action в компонентах Vue. Поскольку модули Vuex с пространством имен уже используются, мы сначала импортируем пространство имен из vuex-class, а затем передаем имя модуля для доступа к модулю.

</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import { namespace } from 'vuex-class'
const user = namespace('user')
@Component
export default class User extends Vue {
  @user.State
  public name!: string

  @user.Getter
  public nameUpperCase!: string

  @user.Action
  public updateName!: (newName: string) => void
}
</script>

Код js, эквивалентный ts, выглядит следующим образом

<template>
  <div class="details">
    <div class="username">User: {{ nameUpperCase }}</div>
    <input :value="name" @keydown="updateName($event.target.value)" />
  </div>
</template>
<script>
import { mapState, mapGetters, mapActions} from 'vuex'
export default  {
  computed: {
    ...mapState('user', ['name']),
    ...mapGetters('user', ['nameUpperCase'])
  }  
  methods: {
    ...mapActions('user', ['updateName'])
  }
}
</script>

Ссылаться на

Первый опыт Vue и TypeScript — использование Vuex

vuex-module-decorators

vue-class-component

vue-property-decorator

vuex-class