vue3+ts+pinia

vue3+router+ts+pinia

ts

优势

静态类型检查,提前发现错误

良好的代码提示

需要编译才可以使用

准备工作

  1. 需要node环境

    1. npm下载npm i typescript
    2. 编译单个文件 tsc 文件名 -w (-w自动编译)
    3. 编译整个文件 tsc (需要tsconfig.json)
  2. ts声明变量时会自动判断类型

数据类型

  1. 简单类型

    number、string、boolean、null、undefined
    
  2. 复杂类型

    对象、数组、函数
    
  3. 新增类型

    联合类型  |
    类型别名  type
    接口interface
    字面量类型    相当于常量
    泛型
    void  无返回值
    any 任意类型,会影响别人
    unknown 未知类型,只影响自己
    元祖 [string,number] 固定长度,指定类型的数组
    

普通值

let num:number = 123
let str:string = 'abc'
let bool:boolean = true

对象

let obj:{
    name:string,必须存在属性name
    age?:number,可选属性age
    [propName:string]:any],其他所有字符串属性都是可选的-propName 可以是任意名字
}

数组

let arr:number[] = [1,2,3]
let arr:(number|string)[] = ['a',1,2,3]
let arr:Array<number|string>=['a',1,2,3]

函数

// 普通函数
function fn1(n1: number, n2: number): number {
  return n1 + n2
}
// 箭头函数
let fn2: (n1: number, n2: number) => number
fn2 = (n1, n2) => n1 + n2
// 或者
type fn = (n1: number, n2: number) => number
const fn3: fn = (n1, n2) => n1 + n2
// 箭头函数(整体注释)
const fn4 = (n1:number,n2:number) => number = (n1,n2) => n1 + n2

接口interface

接口是用于定义一个标准,都是抽象的属性和方法(也不完全是),类似于class类

可以重复声明,属性和方法会叠加、可以继承、可以嵌套

// 普通
interface Father {
  name: string
  age?: number
}
interface Father {
  sex: boolean
}
const f: Father = {
  name: 'yj',
  sex:true
}
// 继承
interface Son extends Father {
	kaoshi:number
}
const s:Son = {
	name:'zz',
	kaoshi:99
}
// 嵌套
interface Sun {
	eye:number,
	data:F
}
const sun: Sun = {
  eye: 2,
  data: {
    name: 'yy',
    age:99
  }
}
接口实现
// 接口定义对象的结构,包含属性和方法声明
interface Person {
  name: string; // 必需属性
  age?: number; // 可选属性
  greet(): void; // 抽象方法
  sayHello(): string; // 抽象方法
  walk?(): void; // 可选方法
}

// 实现接口
class Student implements Person {
  name: string;
  age?: number;
  
  constructor(name: string, age?: number) {
    this.name = name;
    this.age = age;
  }
  
  greet() {
    console.log("Hello, I'm " + this.name);
  }
  
  sayHello() {
    return "Hello";
  }
}

// 创建实例
const student = new Student("Alice", 25);
student.greet(); // 输出:Hello, I'm Alice
console.log(student.sayHello()); // 输出:Hello

类型type

不可以重复声明

type Father = {
  name: string
  age?: number
}
const f: Father = {
  name: 'yj',
  age: 19
}
type Son = Father & {
  sex: boolean
}
const s: Son = {
  name: 'zz',
  age: 29,
  sex: true
}

抽象类、抽象方法abstract

abstract class Person {
    abstract sayHei():void // 这个抽象类,只能被继承,不能被实例化
}
let p = new Person() // 不允许,只能被继承
class Man extends Person{
    sayHei(){} // 必须重写父类的方法,否则ts报错
} // 允许,可以被继承

修饰符 public 、private 、protected

class P {
    private _name: string
    public _age: number
    protected _sex: number 
    constructor(_name:string,_age:number) { 
        this._name = _name
        this._age = _age
    }
	go1(){
        this.
    }
}
let yj = new P('yj',99)
yj._name = 'zd2' // ts报错,提示,私有的_name属性无法控制
yj._age = 999    // ts不报错,公共属性可以修改
console.log(yj);

class P {
    private name: string
    public age: number
    protected sex: number
    constructor(name: string, age: number, sex: number) {
        this.name = name
        this.age = age
        this.sex = sex
    }
    changeSex() {
        this.sex = 999
    }
}
class PPPP extends P { 
    changeSex() { 
        this.sex = 999
    }
}

let yj = new P('yj',9,0)
let yjj = new PPPP('yj',9,0)
yj.name = 'yjj' // ts报错,提示,属性name是私有的,只能在当前类中修改
yj.age = 99
yj.sex = 1 // ts报错,提示,属性sex受到保护,只能在当前类和子类中修改
yj.changeSex()  
yjj.changeSex()

断言(欺骗ts)

const link = document.qs('link') as HTMLAnchorElement
link.可访问链接元素身上的方法

泛型

// 对象和泛型
interface User {
  token: string
  id: number
}
interface List {
  arr1: number[]
  arr2: Array<number>
}
interface ResData<T> {
  code: number
  message: string
  data: T
}
const userRes: ResData<User> = {
  code: 100,
  message: 'ok',
  data: {
    token: 'asd',
    id: 1
  }
}
const listRes: ResData<List> = {
  code: 100,
  message: 'ok',
  data: {
    arr1: [1],
    arr2: [1]
  }
}

// type和interface基本相同
// 函数和泛型
function Myjoin<T>(len: number, value: T): void {
  const arr = []
  for (let i = 0; i < len; i++) {
    arr[i] = value
  }
  console.log(arr)
}
const res = Myjoin<string>(5, 'c')
const res2 = Myjoin<number>(3, 4)

pick挑选属性

// Pick 可以从一个对象类型中 取出某些属性
type Person = {
  name: string
  age: number
  sex: 0|1
}
type PickPerson = Pick<Person, 'age'|'sex'>
// PickPerson === { age: string, sex: 0|1 }

###omit去除属性

// Omit 可以从一个对象类型中 排出某些属性
type Person = {
  name: string
  age: number
  sex: 0|1
}
type OmitPerson = Omit<Person, 'age'|'sex'>
// OmitPerson === { name: string }

Partial属性转为可选

type Person = {
name:string
age?:number
sex?:0|1
}
type PartialPerson = Partial<Person>
// PartialPerson 
{name? age? sex?}

Required属性转为必选

type Person = {
name:string
age?:number
sex?:0|1
}
type RequiredPerson = Required<Person>
// RequiredPerson 
{name age sex}

keyof 提取所有属性

interface Person {
  name: string;
  age: number;
  id: number;
}

// Person 所有键的联合类型
type Keys = keyof Person; // 等效于 "name" | "age" | "id"
// 相当于
interface Keys {
  name: string;
  age: number;
  id: number;
}

enum 枚举

// 不需要直接写入常量,比如1234具体值(没有语义),而是用fx.单词还获取数字(有语义)
// 枚举具有默认值
enum fx {
  left = 1,
  right = 2,
  top = 3,
  bottom = 4
}
console.log(fx.right)

告诉ts是全局变量

/* global 变量名 */
后续的该变量名就不会提示引入错误,被TS认为是已经被全局引入过

tsconfig.json

ts的配置文件,直接放在根目录

{
	"include":["./src/**/*"], // 需要编译的路径
    "exclude":["./dist/**/*"], // 不需要编译的路径
    "extends":"./config/base", //继承其他的规则
    "files":["core.ts","sys.ts"], // 指定编译文件
    "compilerOptions": {
        "target": "ES6",//编译指定es版本  ts=>js
        "module": "ESNext",//编译指定模式es6、commonjs
        // "lib": [],
        "outDir": "dist2", //编译保存的文件夹,
        // "outFile": "./dist/app.js", //编译合并保存文件
        "allowJs": true, //是否编译js文件(文件夹中除了ts之外可能还存在js文件,是否一起编译了)
        "checkJs": true, //是否检查js代码符合规范
        "removeComments": true, //是否移出注释
        "noEmit": false ,// 是否生成编译后的文件
        "noEmitOnError": true, //有错误时,不编译生成文件
        "strict": true,//所有严格模式的总开关,开启后,所有相关属性全部打开和关闭(优先级没有单独写高)
        "alwaysStrict": false,// 开启严格模式 use strict
        "noImplicitAny": true,// 不允许出现默认any类型
        "noImplicitThis": true, // 不允许出现不明确类型的this
        "strictNullChecks": true // 严格的检验是否为空,万一什么东西没获取到
    }
}

vue3 基础语法

reactive-响应式(适用于对象)

import { reactive } from "vue"; 
const state = reactive({ name: 'tom', age: 18 })
state.name++
{{state.name}}

ref-响应式(适用于简单数据)

import { ref } from "vue"; 
const num = ref(100)
num.value++
{{num}}

computed

import { ref, computed } from "vue";
let n1 = ref(10)
let n2 = ref(20)
const sum = computed(()=>{
	return n1.value+n2.value
})
{{sum}}

watch

import { reactive, watch } from "vue";
const state = reactive({
	n1:10,
	n2:20
})
// 监听一个
watch(state.n1,(newV,oldV)=>{
	console.log(newV,oldV)
})
// 监听多个
watch([state.n1,state.n2],(newV,oldV)=>{
	console.log(newV,oldV)//newV、oldV都是数组
})
// 监听对象(深度监听)
watch(state,(newV,oldV)=>{
	console.log(newV,oldV)//newV、oldV都是数组
},{
deep:true,
immediate:true
})

ref-获取DOM

// Vue js
import { ref } from 'vue'
const dom = ref(null) 
dom.value.innerHTML = 换一个标题

// Vue html
<h1 ref="dom">我是标题</h1>

defineExpose

使用:暴露组件方法和属性—defineExpose({})

// fatherVue js
import { ref } from 'vue'
import HomeView from './views/HomeView.vue';
const dom = ref(null) 
调用子级属性和方法时,必须先在子级中暴露
dom.value.conut++
dom.value.fn()

// fatherVue html
<HomeView ref="dom"/>
// sonVue js
const count = ref(0)
const fn = () => {
  console.log('方法')
}
import { ref } from 'vue'
defineExpose({count,fn}) // 暴露属性和方法count和fn

defineProps

js使用:接收父组件的传递的属性—defineProps({})

// fatherVue js
import { ref } from 'vue'
import HomeView from './views/HomeView.vue';
const num = ref(1)
const state = ref({
  name:'yj',age:19
})

// fatherVue html
<HomeView :fstate="state" :fnum="num"/>
// sonVue js
const count = ref(0)
const fn = () => {
  console.log('方法')
}
import { ref } from 'vue'
// 接收属性----js
const props = defineProps({
  fnum:Number,fstate:Object
})

// 接收属性----ts
const props = defineProps<{fnum:number,fstate:Object}>()

props.fnum
props.fstaet

//sonVue html
{{fnum}}---{{fstate}}

defineEmits

使用:接收父组件的传递的属性—defineEmits([])

// fatherVue js
import { ref } from 'vue'
import HomeView from './views/HomeView.vue';
const num = ref(1)
const cfnum = v => {
  console.log(v);
  num.value+=parseInt(v)
}

// fatherVue html
<HomeView @cfnum="cfnum" :fnum="num"/>
// sonVue js
defineProps({
  fnum:Number
})
// 接收属性----js
const emit = defineEmits(['cfnum'])

// 接收属性----ts
const emit = defineEmits<{(e:'cfnum',fnum:number):void}>()

const cfnum = ()=>{
  emit('cfnum','100')
}
//sonVue html
<button @click="cfnum">btn</button>

provide、inject跨组件传值

// yeyeVue
<script setup>
import { provide, ref } from 'vue';
import ParentCom from './ParentCom.vue';

// 1. app组件数据传递给child
const count = ref(0);
provide('count', count);

// 2. app组件函数传递给child,调用的时候可以回传数据
const updateCount = (num) => {
  count.value += num;
};
provide('updateCount', updateCount);
</script>

<template>
  <div
    class="app-page"
    style="border: 10px solid #ccc; padding: 50px; width: 600px"
  >
    app 组件 {{ count }} updateCount
    <ParentCom />
  </div>
</template>

// sunVue 
<script setup>
const count = inject('count');
const updateCount = inject('updateCount');
</script>

<template>
  <div class="child-page" style="padding: 50px; border: 10px solid #ccc">
    child 组件 {{ count }} <button @click="updateCount(100)">修改count</button>
  </div>
</template>

toRefs解构保持响应式

import { reactive, toRefs } from "vue";
const user = reactive({ name: "tom", age: 18 });
const { name, age } = toRefs(user)

router 路由

  1. 路由抽离单独文件 router/index.ts

  2. router/index.ts引入路由

    import { createRouter, createWebHistory } from 'vue-router'
    
  3. router/index.ts 创建路由

    const router = createRouter({
      history: createWebHistory(import.meta.env.BASE_URL),
      routes: [
        {
          path: '/login',
          name: 'login',
          component: () => import('@/views/login/index.vue'),
          meta: {
            title: '登录'
          }
        }
      ]
    })
    
  4. router/index.ts 路由拦截器

    router.beforeEach((to) => {
      
    })
    router.afterEach((to) => {
    
    })
    
  5. 暴露router,让vue注册

    import router from './router'
    app.use(router)
    

    composables

    类似于vue2的mixins ,抽离公共复用的js

    优势

    1. 多个mixins 时,好追溯,知道该方法属于谁
    2. 防止命名被覆盖
    // 定义的composables函数  count.js
    import { onMounted, ref } from 'vue'
    
    export const useCount = () => {
        const num1 = ref(0)
        const num2 = ref(0)
        const sum = ref(0)
        const count = () => {
            sum.value = +num1.value + +num2.value
            console.log('ok')
        }
        onMounted(() => {
            console.log('可以调用生命周期函数')
        })
        return {
            num1,
            num2,
            sum,
            count
        }
    }
    
    
    // 使用 composables函数  A.vue
    导入 
    import { useCount } from '@/composables/count.js'
    const { num1, num2, sum, count } = useCount()
    使用
     <input type="text" v-model.number.trim="num1" />
     <input type="text" v-model.number.trim="num2" />
     {{ num1 }} +{{ num2 }} = {{ sum }}
     <button @click="count">计算</button>
    

pinia 状态管理

  1. 下载

    npm i pinia
    
  2. 引入、注册

    // main.ts
    import { createPinia } from 'pinia'
    const pinia = createPinia()
    app.use(pinia)	
    
  3. 定义数据状态(组合式api代码)

    import { defineStore } from 'pinia'
    import { ref,computed } from 'vue'
    // useChannelStore 尽量这个格式起名字
    // channel 为模块唯一id,和浏览器插件挂钩
    // num 为原vuex的state
    // dbNum 为原vuex的getter
    // addNum、addNumDelay 为原vuex的mutation、action方法,但pinia方法中没有mutation,默认都是action,所以同步和异步为一个方法
    export const useChannelStore = defineStore('channel',()=>{
        const num = ref<number>(0)
        const addNum = (n:number) =>{
            num.value+= n
        }
        const addNumDelay = (n:number) =>{
            setTimeout(()=>{
                num.value+= n
            },1000)
        }
        const dbNum = computed(()=>num.value*2)
        return {
            num,addNum,addNumDelay,dbNum
        }
    })
    
  4. 使用数据状态

    import {useChannelStore} from '../store/chanelStore'
    import { storeToRefs } from 'pinia'
    const store = useChannelStore()
    const onBtn = ()=>{
        store.addNum(10)
    }
    const onBtnDelay = ()=>{
        store.addNumDelay(10)
    }
    // 直接解构使用num,dbNum不是响应式数据,使用storeToRefs方便解构后使用num和dbNum
    const { num,dbNum } = storeToRefs(store)
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值