Vue项目中使用

前面两篇介绍过TypeScript基础和较深入的东西,本章介绍如何在Vue项目中使用。

项目创建

创建项目直接使用Vue-cli创建

下面是步骤:

1.运行vuecli,

2.选择合适的目录创建项目

3.输入项目名并,选择包管理器,输入git仓库初始化内容

4.设置预设,如果你之前有合适的预设,可以设置该预设,这里选择手动

5.选择功能,其中TypeScript和babel必选,其他功能视项目而定:

6.设置配置,开启类样式组件语法(第一项),选择eslint配置为ESLint+Standard(第五项),开启保存时检查和修复代码

7.创建项目

8.安装一些插件

编辑器文件支持设置

这里以我们以后统一使用的Webstrom为例:

找到Editor>File and COde Templates

新建一个代码模板,输入名称,扩展名为vue,选择根据样式重新设置格式、选择启用该模板

内容区域输入:

<template lang="pug">
#[[$END$]]#
</template> <script lang="ts">
import { Component, Vue } from 'vue-property-decorator' @Component
export default class ${COMPONENT_NAME} extends Vue { }
</script> <style lang="stylus" rel="stylesheet/stylus" module> </style>

点击应用之后,新建文件时选择刚建立的模板:

因为选择的是类样式语法,所以需要填入类名:

修改eslint、编辑器配置

修改eslint配置文件以支持检查TypeScript文件

.eslintrc.js文件的parserOptions选项中新增如下代码:

parser: '@typescript-eslint/parser'

修改编辑器配置以支持保存时自动修复代码

webstrom强大之处是对各种技术的支持,比如eslint检查代码。正常情况下,我们需要通过命令行检查代码,这非常麻烦,不过webstrom能够配置eslint,编辑器内检查不合eslint配置的代码,并且支持保存时修复。配置如下:

修改声明文件

对于我们自定义的插件、全局方法、全局变量等,TypeScript并不知道他们,为了让TypeScript认识他们,我们可以通过声明文件告诉TypeScript,如果使用model样式时的$style,我们修改shims-tsx.d.ts文件,在行末添加下面代码:

declare module 'vue/types/vue' {
interface Vue {
$style: {
[key: string]: string;
};
} interface VueConstructor {
$style: {
[key: string]: string;
};
}
}

对于其他内容和上面方法类似

组件中使用

基本用法

因为使用类样式写组件中的js,所以写法上会略有不同,但是本质上还是不变的。

组件引用

组件引用通过传递参数components给装饰符@Component

@Component({
components: {
MapLegend: () => import('@/components/legend/index.vue')
}
})

过滤器

过滤器和组件类似,通过传递filters参数,filters对象内定义局部过滤器:

@Component({
filters: {
dateFormat (date:Date) {
return dateFormat(date)
}
}
})

指令

局部指令和过滤器类似,通过@Component装饰器传递参数directives

@Component({
directives:{
focus: {
inserted: function (el) {
el.focus()
}
}
}
})

props

props不再通过对象属性形式定义,而是通过@Prop装饰器定义,其配置内容通过参数形式传入装饰器:

@Component
export default class Test extends Vue {
@Prop({
type:String,
default:'no name',
required:false
}) name!:string mounted(){
console.log(name)
}
}

props同步版

通过@PropSync可以创建一个props属性的同步版本(即:变量改变,所对应的props属性也会随之改变):

@Component
export default class Test extends Vue {
@PropSync('name',{
type:String,
default:'no name',
required:false
}) name!:string mounted(){
this.name='nichols'
}
}

侦听器(watch)

类似的,侦听器通过@Watch装饰器定义,装饰器接收两个参数,第一个监视哪个变量,第二个其他配置:

@Component
export default class Test extends Vue {
isShow=false
@Watch('isShow',{
deep:true,
immediate:true
})
onIsShowChange(val:boolean,newVal:boolean){ }
}

侦听器同样可以被当做方法调用,只是执行其内部逻辑:

  mounted(){
this.onIsShowChange(true,false)
}

emit

在组件中触发事件让父组件侦听到是一个非常常用的操作,通过@Emit装饰符定义,所定义的函数可以被当做普通函数调用:

@Component
export default class Test extends Vue {
name = '' @Emit('change')
onChange (name: string) {
this.name = name
} mounted () {
this.onChange('nichols')
}
}

其中如果有返回值,则返回值会作为触发的参数放在前面,而传入参数会放到返回值后面

ref

定义ref使用@Ref装饰器定义:

@Component
export default class Test extends Vue {
name = '' @Ref('form') form!:HTMLElement mounted(){
console.log(this.form.offsetHeight)
}
}

data

对于组件内的数据,我们可以直接使用类属性定义组件的数据:

@Component
export default class Test extends Vue {
isShow = false
form: {
username: string;
password: string;
} = {
username: '',
password: ''
} mounted () {
this.isShow = true
}
}

函数(methods)

函数与data定义类似,为类添加一个方法即可:

@Component
export default class Test extends Vue {
log(){
// ....
}
}

计算属性

而计算属性,则是类的存取器的写法(gettersetter,对应Vue的gettersetter):

@Component
export default class Test extends Vue {
lastName = '尼古拉斯'
firstName = '赵四' get name (): string {
return `${this.firstName}·${this.lastName}`
} set name (name: string) {
const names = name.split('·')
this.firstName = names[0]
this.lastName = names[0]
}
}

生命周期

可以直接定义所对应的钩子名称,或者借助vue-class-component/hooks.d.ts完成:

@Component
export default class Test extends Vue {
mounted () {
} created () {
} updated () {
} beforeDestroy () {
} destroyed () {
}
}

更加详细的内容

更详细参考vue-property-decorator文档

类型声明

src目录下types目录下,创建index.d.ts(或者更详细的文件名),然后定义类型,这里以扩展Event为例

interface Event{
DataTransfer:{
setData():void
}
}

为了避免全局变量混乱,可以使用export导出我们想要被外部访问的声明:

export interface User{
id:string;
name:string;
realName:string;
}

需要使用时,再在需要使用的地方导入即可:

import { User } from '@/types/user'

@Component
export default class Test extends Vue {
user:User={
id: '',
name: '',
realName: ''
}
}

旧项目的迁移

安装插件

1.启动vue ui(一把梭,就是干!),在插件项中点击添加插件,

2.搜索TypeScript,选择@vue/cli-pluging-typescript,点击安装即可

修改组件

1.script标签添加属性lang="ts"

2.组件引入添加.vue后缀名

3.修改默认导出为类样式:

export default {
name:'Component1'
}

修改为:

@Component
export default class Component1 extends Vue{
}

4.按照基本用法,将对应的数据更改为类样式

5.按照编辑器报错提示添加或者修改类型注释

修改js文件

1.js文件后缀改为.ts

2.添加类型约束

vuex的使用

vuex和vue组件使用方式类似,使用类样式+装饰器的形式定义,使用的依赖是vuex-module-decoratorsvuex-class

安装

yarn add vuex-module-decorators vuex-class
npm i vuex-module-decorators vuex-class

创建Store

Store的创建和常规创建方式一致,只是Vuex.Store参数中无需传入任何参数:

import Vue from 'vue'
import Vuex from 'vuex'
import User from '@/store/modules/user'
import getters from '@/store/getters' Vue.use(Vuex) export default new Vuex.Store({
})

定义模块

@Module

使用@Module定义一个vuex模块,接收如下参数:

属性

数据类型

描述

name

string

模块的名称(如果有名称空间)

namespaced

boolean

模块是否具有名称空间

stateFactory

boolean

是否开启状态工厂(方便模块复用)

dynamic

true

如果这是一个动态模块(在创建存储后添加到存储)

store

Store<any>

将注入此模块的存储区(用于动态模块)

preserveState

boolean

如果启用此选项,则加载模块时将保留状态

创建模块语法如下:

import { VuexModule } from 'vuex-module-decorators'
@Module({
dynamic: true,//启用动态模块
name: 'User',
store,//注入store
namespaced: true,
stateFactory: true//开启工厂模式
})
export default class User extends VuexModule {
}

state

state的定义和组件中的data定义类似:

@Module({
dynamic: true,//启用动态模块
name: 'User',
store,//注入store
namespaced: true,
stateFactory: true//开启工厂模式
})
export default class User extends VuexModule {
token = getToken()
}

上面代码和下面代码效果一样:

export default {
state:{
token: getToken()
},
namespaced:true
}

@Mutation

mutation的定义使用@Mutation装饰器定义:

@Module({
dynamic: true,//启用动态模块
name: 'User',
store,//注入store
namespaced: true,
stateFactory: true//开启工厂模式
})
export default class User extends VuexModule {
token = getToken() @Mutation
setToken (token: string) {
this.token = token
token ? setToken(token) : deleteToken()
}
}

@Action

使用@Action装饰器定义action,该装饰器接收三个参数:

参数名

类型

描述

commit

string

所提交的荷载

rawError

boolean

是否打印原始错误类型(默认会对报错信息进行包装)

root

boolean

是否允许提交根荷载

如果不传入参数,需要手动提交荷载:

@Module({
dynamic: true,//启用动态模块
name: 'User',
store,//注入store
namespaced: true,
stateFactory: true//开启工厂模式
})
export default class User extends VuexModule {
token = getToken() @Mutation
setToken (token: string) {
this.token = token
token ? setToken(token) : deleteToken()
} @Action
async login () {
this.context.commit('setToken', 'token')
router.replace('/')
}
}

如果指定提交的荷载名,可通过函数的返回值设定荷载值:

@Module({
dynamic: true,//启用动态模块
name: 'User',
store,//注入store
namespaced: true,
stateFactory: true//开启工厂模式
})
export default class User extends VuexModule {
token = getToken() @Mutation
setToken (token: string) {
this.token = token
token ? setToken(token) : deleteToken()
} @Action({commit:'setToken'})
async login ():string {
router.replace('/')
return 'token'
}
}

@MutationAction

有时候简单地数据操作,mutation会显得有点多余,这时候,我们可以使用@MutationAction装饰器将mutatioin和action合二为一,用此装饰器定义的action会同时定义并提交荷载:

@Module({
dynamic: true,//启用动态模块
name: 'User',
store,//注入store
namespaced: true,
stateFactory: true//开启工厂模式
})
export default class User extends VuexModule {
testStr = '' @MutationAction({ mutate: ['testStr'] })
async setStr () {
return new Promise<{ testStr: string }>(resolve => {
resolve({
testStr: 'test'
})
})
}
}

需要注意的是:返回对象的数据结构必须和指定的参数名一致

getter

getter的定义和Vue组件中的计算属性定义类似,使用get前置于方法名:

@Module
class MyModule extends VuexModule {
wheels = 2 get axles() {
return this.wheels / 2
}
}

完整示例

import {
deleteRefreshToken,
deleteToken,
deleteUserInfo,
getRefreshToken,
getToken,
getUserInfo,
setRefreshToken,
setToken,
setUserInfo
} from '@/utils/auth'
import { UserInfo } from '@/types/user'
import router from '@/router'
import { Action, Module, Mutation, MutationAction, VuexModule } from 'vuex-module-decorators' @Module({
dynamic: true,//启用动态模块,模块将在调用getModule时注册
name: 'User',
store,//注入store
namespaced: true,
stateFactory: true//开启工厂模式
})
export default class User extends VuexModule {
token = getToken()
refreshToken = getRefreshToken()
userInfo: UserInfo | null = getUserInfo()
testStr = '' @Mutation
setToken (token: string) {
this.token = token
token ? setToken(token) : deleteToken()
} @Mutation
setRefreshToken (token: string) {
this.refreshToken = token
token ? setRefreshToken(token) : deleteRefreshToken()
} @Mutation
setUserInfo (user: UserInfo | null) {
this.userInfo = user
user ? setUserInfo(user) : deleteUserInfo()
} @MutationAction({ mutate: ['testStr'] })
async setStr () {
return new Promise<{ testStr: string }>(resolve => {
resolve({
testStr: 'test'
})
})
} @Action
async login () {
this.context.commit('setToken', 'token')
this.context.commit('setRefreshToken', 'refreshToken')
this.context.commit('setUserInfo', {})
router.replace('/')
} @Action
async loginOut () {
this.context.commit('setToken', '')
this.context.commit('setRefreshToken', '')
this.context.commit('setUserInfo', null)
router.replace('/login')
}
}

组件中使用

组件中通过getModule()方法进行获取到模块,可以通过定义计算属性以使用state:

import { Component, Vue } from 'vue-property-decorator'
import User from '@/store/modules/user'
import { getModule } from 'vuex-module-decorators'
import { namespace } from 'vuex-class' let user:User = getModule(User) @Component
export default class test extends Vue {
//动态数据,使用user.userInfo获取的并不是响应式数据
@namespace('User').State('userInfo') userInfo: UserInfo login ():void {
console.log(user.testStr)
user.login()
} get token ():string {
return user.token
} mounted ():void { }
}

小程序中使用

小程序中使用TypeScript比较简单,在创建项目时选择语言为TypeScript,其他的和Vue类似项目类似

不同的是,Vue项目会自动编译TypeScript,而小程序需要手动编译ts文件,这显得有点麻烦,所以我们可以使用webstrom开发小程序:

安装小程序插件,让webstrom支持小程序语法:File>Setting>Plugins,搜索Wechat mini programs upport,完成之后重启webstrom,这时候我们可以看到在右键菜单New那一项里面多了两个小程序选项:

配置ts文件自动编译:File>Setting>Languages & Frameworks>TypeScript,选中改变时重新编译:

扩展

本系列文章全面结合项目编写,如果你还想深入学习TypeScript的话可以看下面的网站:

TypeScript中文网

TypeScript 入门教程

TypeScript 学习资源合集

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

工作记录:TypeScript从入门到项目实战(项目篇)的更多相关文章

  1. mxgraph进阶(三)Web绘图——mxGraph项目实战(精华篇)

    Web绘图--mxGraph项目实战(精华篇) 声明     本文部分内容所属论文现已发表,请慎重对待. 需求 由于小论文实验需求,需要实现根据用户日志提取出行为序列,然后根据行为序列生成有向图的形式 ...

  2. 前端开发工程师 - 06.Mini项目实战 - 项目简介

    第6章--Mini项目实战 项目简介 Mini项目简介-Ego社区开发 回顾: 页面制作 页面架构 JavaScript程序设计 DOM编程艺术 产品前端架构 实践课Mini项目--Ego: 主题:漫 ...

  3. 08Vue.js快速入门-Vue综合实战项目

    8.1. 前置知识学习 npm 学习 官方文档 推荐资料 npm入门 npm介绍 需要了解的知识点 package.json 文件相关配置选项 npm 本地安装.全局安装.本地开发安装等区别及相关命令 ...

  4. TensorFlow 中文资源全集,官方网站,安装教程,入门教程,实战项目,学习路径。

    Awesome-TensorFlow-Chinese TensorFlow 中文资源全集,学习路径推荐: 官方网站,初步了解. 安装教程,安装之后跑起来. 入门教程,简单的模型学习和运行. 实战项目, ...

  5. TensorFlow 中文资源精选,官方网站,安装教程,入门教程,实战项目,学习路径。

    Awesome-TensorFlow-Chinese TensorFlow 中文资源全集,学习路径推荐: 官方网站,初步了解. 安装教程,安装之后跑起来. 入门教程,简单的模型学习和运行. 实战项目, ...

  6. 彩虹女神跃长空,Go语言进阶之Go语言高性能Web框架Iris项目实战-项目入口与路由EP01

    书接上回,我们已经安装好Iris框架,并且构建好了Iris项目,同时配置了fresh自动监控项目的实时编译,万事俱备,只欠东风,彩虹女神蓄势待发.现在我们来看看Iris的基础功能,如何编写项目入口文件 ...

  7. iOS开发——项目实战OC篇&类QQ黏性按钮(封装)

    类QQ粘性按钮(封装) 那个,先来说说原理吧: 这里原理就是,在界面设置两个控件一个按钮在上面,一个View在下面(同样大小),当我们拖动按钮的时候显示下面的View,view不移动,但是会根据按钮中 ...

  8. Ant Design Vue Pro 项目实战-项目初始化(一)

    写在前面 时间真快,转眼又是新的一年.随着前后端技术的不断更新迭代,尤其是前端,在目前前后端分离开发模式这样的一个大环境下,交互性.兼容性等传统的开发模式已经显得有些吃力.之前一直用的是react,随 ...

  9. Asp.Net Core 2.0 项目实战(9) 日志记录,基于Nlog或Microsoft.Extensions.Logging的实现及调用实例

    本文目录 1. Net下日志记录 2. NLog的使用     2.1 添加nuget引用NLog.Web.AspNetCore     2.2 配置文件设置     2.3 依赖配置及调用     ...

  10. net core体系-web应用程序-4asp.net core2.0 项目实战(1)-11项目日志解决方案

    本文目录1. Net下日志记录2. NLog的使用    2.1 添加nuget引用NLog.Web.AspNetCore    2.2 配置文件设置    2.3 依赖配置及调用    2.4 日志 ...

随机推荐

  1. Python-单引号、双引号和三引号的作用和区别

    (一).作用 1. 单引号:单引号内部为一串字符(str). 2. 双引号:双引号内部为一串字符,双引号内的字符串可以出现单引号(相当于双引号优先级更高),但不能嵌套双引号. 3. 三引号:用于换行输 ...

  2. JS leetcode 有序数组的平方 题解分析,灵活运用Math.pow与Math.abs方法

    壹 ❀ 引 郁闷的周一,晚上来做一道简单的算法题提提神,题目来自leetcode977. 有序数组的平方,题目描述如下: 给定一个按非递减顺序排序的整数数组 A,返回每个数字的平方组成的新数组,要求也 ...

  3. NVME学习笔记杂谈—名词定义

    1.5 定义1.5.1 Admin QueueAdmin Queue 是标识符为 0 的 Submission Queue 和 Completion Queue .Admin Submission Q ...

  4. ROS2 humble交叉编译环境配置

    目录 配置 toolchain文件: 库文件 交叉编译指令: 问题点: 1.find_package找不到自定义依赖包的问题 2.libarmadillo.so.10: undefined refer ...

  5. 反射,装饰器,类当中的方法,property---day24

    1.反射 # ### 反射(针对于类对象 模块) '''概念:通过字符串去操作类对象或者模块当中的成员(属性方法)''' class Man(): pass class Woman(): pass c ...

  6. day04---虚拟主机网络配置的三种模式介绍

    课程大纲 补充:安装系统过程中 分区的知识 1.虚拟软件使用方法 2.操作系统网络配置 3.虚拟主机网络设置 4.操作系统远程连接 5.远程连接排错思路 补充:安装系统过程中 分区的知识 1.企业常见 ...

  7. VMware虚拟机Ubuntu系统如何占满整个屏幕

    VMware虚拟机Ubuntu系统分辨率调节 桌面右击--Disoplay Settings 选择一个跟本机系统一样或者相近的.(本机小米笔记本win11,具体看自己的情况) 结束.

  8. 2-Django之三板斧

    HttpResponse 返回字符串类型的数据 HttpResponse: 这是 Django 自带的类,用于构建基本的 HTTP 响应 我的app名称是demo,我们先按照正常的流程,在views中 ...

  9. Simulink模型指标分析与模型重构的最佳实践 - 软件模型质量保证不可忽视的一环

    在基于模型的开发中,优质的模型架构是生成优质代码的必要前提.静态模型分析对于模型的质量保证有着至关重要的作用,同时建模规范已在业内有着广泛而成熟的应用.然而建模规范并非模型设计原则合规性的唯一考量标准 ...

  10. 【Azure 应用服务】遇见“无法创建hybrid connection for App Service”的解决办法

    Hybrid Connection (混合连接) 在两个联网应用程序之间启用了双向.请求-响应和二进制流通信以及简单的数据报流.通过混合连接,可以实现应用部署在公网环境中,而数据库保存在本地私网环境中 ...