предисловие
Уже 2020 год, а я еще не начал использовать ts в проекте, пользуюсь паникой дома, чтобы попробовать ts в первый раз. Ниже я покажу, как создать приложение Vue + TypeScript с помощью Vue CLI.
Инициализировать проект
Vue create ts-vue
выберитеManually select featuresЗдесь я выбрал Babel, TypeScript, Router, Vuex, препроцессоры CSS, Linter/Formatter.Затем следуйте инструкциям по установке, окончательная конфигурация выглядит следующим образом.
После установки следуйте подсказкам
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 для написания из следующих пяти аспектов.
- Class-based components
- Data, props, computed properties, methods, watchers, and emit
- Lifecycle hooks
- Mixins
- 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>