文章目录
vite搭建vue3+ts+vue-router+scss
两种创建方式
npm init @vitejs/app
这种安装方式包括ts安装,但是确保node.js版本>=10.16.0,否则会出现报错,
解决方法参考博文:https://blog.csdn.net/Sun_Shydeo/article/details/125983070
npm init vite-app <project-name>
需要自己手动配置安装ts
配置typescript
-
安装ts
npm i -g typescript
-
初始化 tsconfig.json
npx tsc --init
-
将main.js修改为main.ts,所有引用的地方也需要改为main.ts
-
页面中的
<script>
修改为<script lang="ts">
-
配置tsconfig,json
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"moduleResolution": "Node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["ESNext", "DOM"],
"skipLibCheck": true,
"baseUrl": ".",
"paths": {
"@/*":["src/*"],
"components":["src/components/*"],
}
},
}
- 配置vite.config.ts
import {
defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import path from "path";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
});
安装css预处理器
-
npm i -D sass 下载处理器
-
由于直接在main.ts里导入的话,style标签会访问不到全局Scss中的变量和规则,需要在vite.config.ts中导入全局Scss
import {
defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import path from "path";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
// css预处理器
css: {
preprocessorOptions: {
scss: {
additionalData: `@use "@/styles/index.scss" as *`,
},
},
}
});
安装vue-router
- npm i vue-router
- 在src下的router目录中新建Index.ts
import {
createRouter,
createWebHistory
} from 'vue-router'
const routes = [
{
path: "/", redirect: "/home" },
{
path: "/home", component: () => import("@/components/HelloWorld.vue") }
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
export default router
- 在main.ts中挂载router
import {
createApp } from 'vue'
import App from './App.vue'
import router from "@/router";
createApp(App).use(router).mount('#app')
TS的类型
直接使用字面量进行声明(少用)
let b: 'hello' | 'flase'; //b可以是'hello'也可以是'false'
let c: boolean | string; //联合类型 |表示或,&表示与
any表示任意类型(不推荐)
一个变量设置类型为any相当于关闭类型检索,如果变量没有指定类型,则TS解析器会自动判断变量的类型为any(隐式any)
unknown表示未知类型
与any类似,unknown变量可以设置任意类型,与any的区别在于,any类型的变量可以赋值给任意变量,unknown是一个类型安全的any,如果不缩小范围,则无法直接赋值给其他变量,这种机制起到了很强的预防性,更安全,这就要求我们必须缩小类型,我们可以使用typeof
、类型断言
等方式来缩小未知范围(s = e as string 或者 s = < string > e)
let c:unknown;
c =1 ;
c = 'number'
let s:string
c= 'hello'
s = c
函数声明
- 常用的结构
function fn():boolean| string{
return '111'
} // 返回布尔类型或者字符串类型
- 当函数永远都不会有返回结果时,可以使用never,常用场景:抛出异常
function fn():never{
throw new Error('11')
}
- 设置函数结构的类型声明 语法:(形参:类型,形参:类型,…)=>返回值
// 正确
let d :(a1:number,b1:number)=>number
d = function(a,b){
return a+b
}
// 报错
let d :(a1:number,b1:number)=>number
d = function(a:string,b:string){
return a+b
}
- 可选参数,在参数名后添加
?
表示参数是可选的,但是注意可选参数后面不允许再出现必填参数
function buildName(firstName: string, lastName?: string) {
if (lastName) {
return firstName + ' ' + lastName;
} else {
return firstName;
}
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');
- 剩余参数
function push(array: any[], ...items: any[]) {
items.forEach(function(item) {
array.push(item);
});
}
let a = [];
push(a, 1, 2, 3);
object表示一个js对象
- {}用来指定对象中可以包含哪些属性,语法:{属性名:属性值,属性名:属性值,…}
- 在属性名后面加上一个?表示属性是可选的
let b : {
name : string,age?:number}
b= {
name:'张三'}
- [属性名:string] : any 表示任意类型的属性
let c : {
name:string,[propName:string]:any}
c = {
name:'李四',age:18,gender:'male'}
Array数组
对数组的定义有两种方式,同时还可以定义联合类型或者指定对象成员的数组
//两种声明方式
let e :string[]
let f : Array<number>
// 定义联合类型数组
let g :(number | string)[]
// 定义指定对象成员数组
interface arrobj{
name:string,
age:number
}
let h:arrobj[] = [{
name:'张三',age:23}]
tuple元组
- 元组用于保存固定长度固定数据类型的数据,可以限制数组元素的个数和类型。元组支持解构赋值
// 语法:[类型,类型]
let g:[string,string]
g = ['hello','e']
- 可选元素,元组支持
?
来声明元组类型可选的参数,语法:[类型,类型?] - 剩余元素,元组的最后一个元素可以是剩余元素,格式为
...X
,剩余元素代表元组类型是开放的,可以有零个或多个额外的元素。
// 表示带有一个 number 元素和任意数量string 类型元素的元组类型
[number, ...string[]]
enum枚举:列举所有可能情况
enum Gender{
male=0,
female=1
}
let i :{
name:string,gender:Gender}
i ={
name:'王五',
gender:Gender.male
}
never:永不存在的值
-
如果一个函数执行时抛出了异常,那么这个函数永远不存在返回值(因为抛出异常会直接中断程序运行,这使得程序运行不到返回值那一步,即具有不可达的终点,也就永不存在返回了);
-
函数中执行无限循环的代码(死循环),使得程序永远无法运行到函数返回值那一步,永不存在返回
-
没有类型是
never
的子类型或可以赋值给never
类型(除了never
本身之外),即使any
也不可以赋值给never
-
使用 never 避免出现新增了联合类型没有对应的实现,目的就是写出类型绝对安全的代码。
类型的别名
type myType = 1|2|3|4
let k :myType
let h :myType
非空断言
一个新的后缀表达式操作符 !
可以用于断言操作对象是非 null 和非 undefined 类型。即x! 将从 x 值域中排除 null 和 undefined 。
注意
null和undefined
默认情况下Null和undefined是所有类型的子类型,可以把null和undefined赋值给其他类型。但如果在tsconfig.json中指定了"strictNullChecks":true
,null 和 undefined 只能赋值给 void 和它们各自的类型。
number和bigint
虽然都表示数字,但是两个类型并不兼容,会抛出一个ts(2322)错误。
object、Object 和 {}
- 小 object 代表的是所有非原始类型,也就是说我们不能把 number、string、boolean、symbol等 原始类型赋值给 object。在严格模式下,null 和 undefined 类型也不能赋给 object。
- 大Object 代表所有拥有 toString、hasOwnProperty 方法的类型,所以所有原始类型、非原始类型都可以赋给 Object。同样,在严格模式下,null 和 undefined 类型也不能赋给 Object。
- {}空对象类型和大 Object 一样,也是表示原始类型和非原始类型的集合,并且在严格模式下,null 和 undefined 也不能赋给 {}
面向对象
类
对象中主要包含了两个部分(属性和方法),直接定义的属性是实例属性,需要通过对象的实例去访问,使用static开头的属性是静态属性(类属性)可以直接访问,readonly表示只读属性,方法和属性类似
<template>
<div class="">实例属性:{
{ person }}</div>
<div class="">静态属性:{
{ Person.age }}</div>
</template>
<script setup lang="ts">
import {} from "vue";
class Person{
// 实例属性
name:string = '孙悟空';
//在属性前使用static 关键字可以定义类属性
static age:number = 18;
}
const person = new Person()
</script>
构造函数
class Dog{
name:string;
age:number;
// 构造函数会在对象创建时调用
constructor(name:string,age:number){
// this表示当前对象
this.name = name,
this.age =age
}
}
const dog1= new Dog("狗1",1)
const dog2 = new Dog("狗2",2)
console.log(dog1,dog2);
继承
关键字:extends
使用继承之后,子类将会拥有父类所有的方法和属性,通过继承可以将多个类中共有的代码写在一个父类中,这样只需要写一次就可以让所有的子类都同事拥有父类的属性,如果在子类中添加了与父类重名的方法,则会重写父类对应的方法。
示例:
class Animals {
name: string;
age: number;
constructor(name: string, age: number) {
(this.name = name), (this.age = age);
}
sayHello() {
console.log("动物在叫");
}
}
class Dog extends Animals {
sayHello() {
console.log(this.name,"旺旺");
}
}
class Cat extends Animals {
sayHello() {
console.log(this.name,"喵喵",);
}
}
const dog1 = new Dog("小狗", 1);
const cat = new Cat("奶牛", 2);
dog1.sayHello();
cat.sayHello();
关键字:super
在类的方法中super表示当前类的父类(超类),如果子类中写了构造函数,则子类构造函数中必须对父类的构造函数进行调用
示例:
class Animals {
name: string;
age: number;
constructor(name: string, age: number) {
(this.name = name), (this.age = age);
}
sayHello() {
console.log("动物在叫");
}
}
class Dog extends Animals {
fur:string;
constructor(name:string,age:number,fur:string){
//调用父类的构造函数
super(name,age)
this.fur = fur
}
sayHello() {
console.log(`${
this.name}是一只${
this.fur}的狗,它${
this.age}岁了`);
}
}
class Cat extends Animals {
sayHello() {
console.log(this.name,"喵喵",);
}
}
const dog1 = new Dog("小狗", 1,'黑色');
const cat = new Cat("奶牛", 2);
dog1.sayHello();
cat.sayHello();
抽象类
关键字:abstract,extends
抽象类无法创建对象,可以被继承,抽象类中可以添加抽象方法,抽象方法没有方法体
abstract class Animal{
name:string;
constructor(name:string){
this.name = name
}
abstract sayHello():void;
}
class Dog extends Animal{
sayHello(){
console.log(this.name,'汪汪汪')
}
}
new Dog('小狗').sayHello()
接口
关键字:interface,implements
接口用来定义一个类结构,在定义类时,限制类的结构,接口中的所有的属性都不能有实际的值,在接口中的所有方法都是抽象方法。
属性的封装
上述所讲的属性是在对象中设置的,属性可以任意的被修改,会导致对象中的数据变得非常不安全,通过在属性前面添加属性的修饰符可以限制属性的访问。
-
private 表示私有属性,只能在类内部进行访问和修改,可以通过类中的方法来访问私有属性
-
public修饰的属性可以在任意位置访问,默认
-
protected受保护的属性,只能在当前类和当前类的子类中访问
-
属性存取器:getter()和setter() 在ts中可以直接写
get name(){}
class Dog{
// private表示私有属性,只有在类中访问
private age:number;
public name : string;
constructor(name:string,age:number){
this.name = name
this.age = age
}
get ages(){
return this.age
}
set ages(value :number){
this.age = value
}
}
const dog = new Dog("小狗",1)
console.log(dog.ages);
泛型
在定义函数或者类时,如果遇到类型不明确时可以使用泛型
// 单个
function fn<T>(a:T):T{
return a;
}
// 多个
function fn<T,K>(a:T,b:K):T{
console.log(b);
return a;
}
// 泛型继承接口或者类
interface Inter{
length:number;
}
function fn<T extends Inter,K>(a:T,b:K):T{
console.log(b);
return a;
}
- 可以直接调用据有泛型的函数
fn(10); //不指定泛型,ts可以自动对类型进行推断
fn<string>('hello');//指定泛型
- 泛型工具类型:
- typeof在类型上下文中获取变量或者属性的类型
- keyof获取某种类型的所有键,其返回类型是联合类型
- in用来遍历枚举类型
- infer声明一个类型变量并对它进行使用,用它取到函数返回值的类型方便之后使用。