课程地址:【Typescript入门并在vue项目中使用】 https://www.bilibili.com/video/BV1A54y117kA/?share_source=copy_web&vd_source=b1cb921b73fe3808550eaf2224d1c155
目录
1 快速了解ts的基础类型
1.1 上
布尔类型boolean、数值类型number、字符串类型string、数组Array<T>或T[]、undefined、null、联合类型(ts中的或 | )、任意类型any、空类型void、接口、对象、属性可选、接口继承(继承1个接口,继承多个接口)、ts中的与&。
// 布尔类型
let boo1: boolean = true;
boo = '123'; // 报错
// 数值类型
let num1: number = 123;
//字符串
let str: string = '123';
// 数组
// 写法1
let arr: Array<number> = [1, 2, 3];
// 写法2
let arr2: number[] = [1, 2, 3];
// undefined、null
let _undefined: undefined = undefined;
let _null: null = null;
// ts中的或|,联合类型
// 只能是所有类型中的某一个
let some_var: number | string | boolean | undefined;
// 以下不会报错
some_var = true;
some_var = 'aaa';
some_var = undefined;
// any,不进行类型校验,可以是任意类型
let any_var: any = 123;
// any可以是任何类型,不再进行类型校验
any_var = true;
// void,主要是针对函数,函数没有return任何值,返回值就是void
function func(arg: number): void {
}
func(1)
function func2(arg: string): boolean {
return false;
}
// 接口,名称预定俗称以I开头,interface
interface IPerson {
name: string,
age: number,
sex: string
}
// 对象:使用接口来定义对象的类型
let obj: IPerson = {
name: 'zyy',
age: 18,
sex: 'male'
}
interface IPerson2 {
name: string,
age: number,
sex?: string // 可选项
}
// 对象:使用接口来定义对象的类型
let obj2: IPerson2 = {
name: 'zyy',
age: 18
}
// 接口继承
interface IPerson3 {
name: string
}
// 继承1个接口
interface ITeacher extends IPerson3 {
hobby: Array<string>,
student: string[]
}
let teacher: ITeacher = {
name: 'zyy',
hobby: ['a', 'b', 'c'],
student: ['d', 'e', 'f']
}
// 继承多个接口
interface IPerson4 {
age: number
}
// 继承多个接口时,逗号分开
interface ITeacher2 extends IPerson3, IPerson4 {
hobby: Array<string>,
student: string[]
}
let teacher2: ITeacher2 = {
name: 'zyy',
hobby: ['a', 'b', 'c'],
student: ['d', 'e', 'f'],
age: 18
}
// ts中的与&
// 具备两个接口的所有属性。
let person4: IPerson3 & IPerson4 = {
name: 'zyy',
age: 19
}
1.2 下
接口-属性不确定,类型不确定、实现接口implements、类型断言、非空断言、枚举(反向映射,枚举赋值)、泛型
// 接口
// 属性不确定
interface IPerson5 {
[propName: string]: any // 索引签名类型
}
let person5: IPerson5 = {
name: 'zyy',
age: 19,
sex: 'female'
}
// implements接口实现
interface IPerson6 {
name: string,
age: number,
sex: string,
getName: () => string,
getAge: () => number
}
class Person implements IPerson6 {
name: string = 'zyy';
age: number = 18;
sex: string = 'female';
getName(): string {
return this.name;
};
getAge(): number {
return this.age;
};
// 类自己的方法
sayHello(): void {
console.log('Hello!');
}
}
// 类型断言
function getLength(str: number | string): number {
// 类型断言,断言str是string类型
if ((str as string).length) {
// 类型断言方式1, 变量后使用as
// return (str as string).length;
// 类型断言方式2,变量前使用<>
return (<string>str).length;
} else {
return str.toString().length;
}
}
// 非空断言
function func3(arg?: string): number {
// !表示arg一定存在
return arg!.length;
// 相当于return arg && arg.length;
// 即若arg存在,返回arg.length,否则返回null/undefined/NaN
}
// 枚举
enum Color {
red,
green,
yellow
}
// 属性的值从0开始自增
Color.red // 0
Color.green // 1
Color.yellow // 2
// 反向映射
Color[0] //返回 'red'
Color[1] //返回 'green'
Color[2] //返回 'yellow'
// 给枚举赋值
enum Color2 {
red = 1,
green, //2
yellow //3
}
enum Color3 {
red,
green = 2, //2
yellow //3
}
// 如果前一个枚举值是字符串,后一个枚举属性必须赋值
enum Color4 {
red,
green = 'green',
yellow = 'yellow'
}
// 泛型
// T表示泛型,一般用T表示,别的字母也可以
function func4<T>(arg: T): void {
}
func4<number>(123);// 定义T为number,则参数只能传number类型的值
2 vue组件新的写法
初始化一个vue项目。
2.1 安装vue cli
安装命令
npm install -g @vue/cli
在vs code的命令行直接执行上述命令即可。
不知道成功了没。
vue cli安装失败,解决npm ERR! code CERT_HAS_EXPIRED npm ERR! errno CERT_HAS_EXPIRED npm ERR! request to-CSDN博客
2.2 通过vue cli初始化项目
通过vue cli初始化项目。
操作。
步骤1:在目标文件夹下,右键,点击Git Bash Here。
步骤2,输入命令和项目名称
这里up给的命令在后面不能通过键盘上下键进行选择。
解决方法:
这时候将 vue create 项目名 这个指令改为 winpty vue.cmd create 项目名 即可。
步骤3,选择默认还是手动选择,这里选择手动选择。
步骤4:选择特性
使用空格进行选择,其中Babel,TypeScript必选,Router和vuex也选上,其他的可选可不选。
步骤5:选择vue.js的版本。
up视频里没有,应该是那个时候还没有vue3(vue3在2020年9月18日出版的,学习的这个视频是2020年9月19日传到Bilibili上的)。
此处选择2.x。
步骤6:这里up没说原因,就输入个y吧
步骤7:使用Babel,去解析JSX,也输入y。还有选择历史模式,也是yes。
步骤8:校验,选择ESlint + Airbnb config吧
步骤9:是保存的时候校验,还是提交的时候修复,都选。
步骤10:配置文件,是放到单独的文件还是package.json中,这里选择单独文件。
步骤11:是否将当前做的选择保存成一个文件方便下次使用。这里是n,不需要。
然后就开始初始化项目了,安装依赖包等。
此时项目里会多了一个文件夹。
步骤12:安装完成,提示两个命令。
① 进入这个目录
② 然后运行项目。
首先进入这个目录
然后运行项目
然后他就会执行构建
构建完成
项目已经启动,打开下面的地址。
项目启动的页面如下。与之前用vue cli初始化的项目是一样的。但是代码是不一样的。
2.3 项目文件
.d.ts文件,类型声明文件。
tsx结尾的文件,可以写jsx的代码。
vue结尾的文件,表示在ts可以识别.vue结尾的文件。
2.4 vue-property-decorator组件
书接上文,代码是不一样的。
使用vs code打开上面新建的项目文件夹
vue-property-decorator 的装饰器主要有以下几个:
@Component
@Watch 监听
@Prop 子组件接收参数
@Model 与@Prop类似,在子组件传参,可以通过v-model传参,子组件接收参数是通过@Model来接收
@Emit 子组件往父组件传递回调函数
import { Component, Vue } from 'vue-property-decorator';
/*
vue-property-decorator 的装饰器
@Component
@Watch 监听
@Prop 子组件接收参数
@Model 与@Prop类似,在子组件传参,可以通过v-model传参,子组件接收参数是通过@Model来接收
@Emit 子组件往父组件传递回调函数
*/
浅了解下@Model装饰器
2.4.0 钩子函数
跟以前一样,在export default ... 里直接写。这里就不写具体的代码了。
2.4.1 @Component装饰器
知识点1:name属性
@Component的name(新写法)相当于export default里的name(老写法)。
知识点2:自定义组件
如果有自定义组件,就写在装饰器@Component的components里。
如果没有自定义组件,可以不写(括号也不需要)
知识点3:新写法
知识点4:data数据
老写法:在export default里,写一个data函数,return一个对象,具体的数据就在return的对象里。
新写法:
知识点5:计算属性
老写法:
新写法:
知识点6:在模板里显示数据
使用vue的模板语法。
效果
补充:eslint报错
报错1:表示字符串应该用单引号而不是双引号。(但是vs code自动会把单引号的字符串改为双引号)
eslint 是一个严格的语法检查工具 ,出现 " Strings must use singlequote" ,就是语法检查引起的。
有两种改法:百度安全验证
饮鸩止渴式做法
知识点7:methods写法
老写法:
新写法:
直接写方法名和方法体,不需要写methods,且methods和计算属性和data都不需要用逗号(,)隔开(写逗号还会报错)。
知识点8:计算属性的set方法
set方法的必要性:当计算属性fullName变化时,对于拼接fullName的firstName和lastName的值也要对应变化。
老写法:
新写法:
modifyFullName是改变fullName的事件处理函数。当fullName改变时,会触发计算属性fullName的set函数,因此firstName和lastName也就会发生变化。
效果
改变之前
点击按钮改变fullName,fullName发生变化,同时firstName和lastName也一起发生变化。
完整代码
<template>
<div class="about">
<h1>This is an about page</h1>
<p>{{ firstName }}</p>
<p>{{ lastName }}</p>
<p>{{ fullName }}</p>
<button @click="modifyFullName">修改fullName</button>
</div>
</template>
<script lang="ts">
/* eslint-disable */
import { Component, Vue } from "vue-property-decorator";
/*
vue-property-decorator 的装饰器
@Component
@Watch 监听
@Prop 子组件接收参数
@Model 与@Prop类似,在子组件传参,可以通过v-model传参,子组件接收参数是通过@Model来接收
@Emit 子组件往父组件传递回调函数
*/
/*
export default {
name: "About",
data() {
return {
firstName: 'z',
lastName: 'yy',
}
},
computed: {
fullName: {
get() {
return this.firstName + ' ' + this.lastName;
},
set(val) {
}
}
},
methods: {
modifyFullName() {
}
}
}
*/
@Component
export default class About extends Vue {
/* eslint-disable */
firstName = "z";
lastName: string = "yy";
// 计算属性
get fullName() {
return this.firstName + " " + this.lastName;
}
set fullName(val) {
// this.fullName变化后,需要对拼接的this.firstName 和 this.lastName进行相应的修改
const arr = val.split(" ");
this.firstName = arr[0];
this.lastName = arr[1];
}
modifyFullName() {
this.fullName = "li si";
}
}
</script>
2.4.2 @Watch装饰器
在上面知识点8例子的背景下,修改fullName时,firstName和lastName也要进行相应修改。通过watch进行监听。
步骤1:引入Watch装饰器。
步骤2:通过watch进行监听firstName的变化。
说明:过程:点击按钮,修改fullName,然后会执行fullName的set方法,修改firstName和lastName的值。 当firstName修改时,通过watch监听firstName,当firstName修改后马上执行onFirstChange方法(方法随便写)。
2.4.3 @Prop装饰器
在自定义组件里接收参数。
1 创建一个自定义组件
步骤1:components里新建组件User.vue。
2 父组件传值
步骤1:在父组件里引入子组件
import User from "../components/User.vue";
注意:在ts里, 引入的自定义组件的位置要写全,不写".vue"会报错。
在装饰器@Component的components属性里配置自定义组件
步骤2:定义用户列表
用接口来实现数组-用户列表的定义。
在模板里使用user组件循环展示user信息。
3 子组件接收参数
老写法和新写法
补充
子组件user的模板
效果
注意:eslint报错:error Expected linebreaks to be ‘LF‘ but found ‘CRLF‘ linebreak-style
解决:
https://blog.csdn.net/qq_41547882/article/details/115458137
2.4.4 @Emit装饰器
实现对用户信息的单条删除。
1、添加删除按钮
给上面的三个user的右边添加删除按钮。
静态效果
2、向父组件Emit一个事件
步骤1:引入Emit装饰器。
import { Component, Vue, Prop, Emit } from "vue-property-decorator";
步骤2:向父组件Emit一个事件
3、父组件接收事件
添加on-remove事件。
事件处理函数remove,打印一下子组件抛出的值。
打印结果。111就是子组件user.vue传出去的参数。
4、子组件传递id供父组件删除用户信息
步骤1:user在remove的时候传递id。
步骤2:remove方法
步骤3:父组件接收到id,删除对应的用户信息。
严格一点,ts里要声明变量的类型。
效果
删除了中间年龄为19的用户信息。
Emit可以不传事件名,不传的话,事件名就是执行的方法名的改写(加短划线)
举例:添加年龄修改的功能。
1、子组件添加年龄修改按钮
2、向父组件emit一个change-age事件
3、父组件处理change-age事件
以及对应的事件处理函数
结果:
2.4.5 @Model装饰器 !!!
当在子组件修改firstName时,父组件的firstName就会同步修改。
1、父组件将firstName传给子组件
2、子组件处理
步骤1 引入Model
import { Component, Vue, Prop, Emit, Model } from "vue-property-decorator";
步骤2 接收v-model传入的属性
步骤3:input框供用户输入父组件传给子组件的值,绑定点击事件。
input框绑定了onChangeFirName事件处理函数,在修改firName的时候会触发onChangeFirName方法
步骤4:当子组件修改firstName时,会emit一个changeFirstName事件(Model里指定的事件)
步骤5:最后,父组件里的firstName的值就会同步修改,父组件不想要接收事件。
结果。
在输入框修改内容,上面的firstName和fullName也会一起修改。
2.4.6 完整代码
可以在vs code终端里运行该项目,要在该项目文件夹下。(由于eslint的语法检查,这里运行失败了)
上面章节有点多,这里给出完整的代码。
AboutView.vue(作为以上案例的父组件)
<template>
<div class="about">
<h1>This is an about page</h1>
<p>{{ firstName }}</p>
<p>{{ lastName }}</p>
<p>{{ fullName }}</p>
<button @click="modifyFullName">修改fullName</button>
<!-- 水平线 -->
<hr />
<!-- v-bind将item所有的属性都传给子组件User.vue -->
<user
v-for="item in userList"
:key="item.id"
v-bind="item"
@on-remove="remove"
@change-age="changeAge"
v-model="firstName"
></user>
</div>
</template>
<script lang="ts">
/* eslint-disable */
import { Component, Vue, Watch } from "vue-property-decorator";
import User from "../components/User.vue";
/*
vue-property-decorator 的装饰器
@Component
@Watch 监听
@Prop 子组件接收参数
@Model 与@Prop类似,在子组件传参,可以通过v-model传参,子组件接收参数是通过@Model来接收
@Emit 子组件往父组件传递回调函数
*/
/*
export default {
name: "About",
data() {
return {
firstName: 'z',
lastName: 'yy',
}
},
computed: {
fullName: {
get() {
return this.firstName + ' ' + this.lastName;
},
set(val) {
}
}
},
methods: {
modifyFullName() {
}
}
}
*/
interface IUser {
id: number;
name: string | number;
age: number;
gender?: string;
}
@Component({
components: {
User,
},
})
export default class About extends Vue {
/* eslint-disable */
firstName = "z";
lastName: string = "yy";
// 用户列表
userList: Array<IUser> = [
{
id: 1,
name: "zyy",
age: 18,
gender: "female",
},
{
id: 2,
name: "zyy",
age: 19,
},
{
id: 3,
name: "zyy",
age: 20,
},
];
// 计算属性
get fullName() {
return this.firstName + " " + this.lastName;
}
set fullName(val) {
// this.fullName变化后,需要对拼接的this.firstName 和 this.lastName进行相应的修改
const arr = val.split(" ");
this.firstName = arr[0];
this.lastName = arr[1];
}
modifyFullName() {
this.fullName = "li si";
}
// 传入要监听的参数
// 过程:点击按钮,修改fullName,然后执行fullName的set方法,修改firstName和lastName
// 当firstName修改时,这里通过watch监听firstName,当firstName修改后马上执行onFirstChange方法(方法随便写)
@Watch("firstName")
onFirstChange(newVal, oldVal) {
console.log(oldVal, newVal);
}
// 钩子函数
created() {}
mounted() {}
remove(id: number) {
// 找到要删除的用户的索引值
const index: number = this.userList.findIndex((user) => user.id === id);
// 删除
this.userList.splice(index, 1);
}
changeAge(id: number) {
// 获取要改变年龄的用户
const user: IUser = this.userList.find((user) => user.id === id);
// 改变该user的年龄
user.age++;
}
}
</script>
User.vue(作为以上案例的子组件)
<template>
<!-- 显示姓名、性别和年龄 -->
<div>
<div>
firName: <input type="text" :value="firName" @input="onChangeFirName" />
</div>
姓名: {{ userName }}, 性别: {{ gender }}, 年龄: {{ age }}
<button @click="changeAge(id)">年龄+1</button>
<button @click="remove(id)">删除</button>
</div>
</template>
<script lang="ts">
import { Component, Vue, Prop, Emit, Model } from "vue-property-decorator";
@Component({
name: "User",
})
/*
export default {
props: {
propsA: Number,
propsB: [String, Number]
}
}
*/
export default class User extends Vue {
get userName() {
return this.name;
}
// 加了个非空断言
@Prop(Number)
id!: number;
@Prop([String, Number])
name!: string | number;
// 指定类型
@Prop({ type: Number })
age!: number;
// 有默认值
@Prop({ type: String, default: "female" })
gender?: string;
// 向父组件emit一个on-remove事件
@Emit("on-remove")
remove(id: number) {
// return可以不写
// 如果没有return的话,默认会把函数的参数传递出去
// return id;
}
@Emit() // Emit括号不写事件,会默认emit一个change-age事件(根据下面的函数名称)
changeAge(id: number) {}
// firstName通过v-model传到user里来。
@Model("changeFirstName", { type: String })
firName!: string;
// input框绑定了onChangeFirName事件处理函数,在修改firName的时候会触发onChangeFirName方法
// 当子组件修改firstName时,会emit一个changeFirstName事件(Model里指定的事件)
@Emit("changeFirstName")
onChangeFirName(e: any) {
// return 修改后的值
return e.target.value;
}
}
</script>
3 vuex的ts写法
p7
vuex,暂时没学过,这part可以跳过(以后看了vuex,可以再看看这块)。
(包括一些@Mutation、@Action等等)
4 ts后台管理框架
是一个后台管理模板,支持typescript,使用了element-ui,也有js版本。
github地址:GitHub - Armour/vue-typescript-admin-template: 🖖 A vue-cli 3.0 + typescript minimal admin template
随便看看。src/views/charts/bar-chart.vue,有学过的一些东西。
有需要可以去了解一下这个框架