TS&OOP DAY02

Vuex Vue官方推荐的全局状态管理器

在脚手架项目的实现过程中,避免不了需要将一些数据存储在全局,方便在任何组件中直接获取并使用的需求。这种需求就非常契合vuex的功能,vuex主要用于将一些数据实现全局存储,需要的时候直接访问vuex即可获取这些数据。

官方文档:https://vuex.vuejs.org/zh/guide/

Vuex和核心js文件: src/store/index.js,提供了vuex内置的5个对象:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  // 此处用于存储全局共享的状态数据
  state: { 
    user: null,  // user用于存储当前登录用户
  },
  // getters用于提供一些方法,方便的获取state中数据的临时计算结果
  // 类似vue中的计算属性:computed
  getters: {
  },
  // mutations用于提供一些方法,修改state中的状态数据
  mutations: {
  },
  actions: {
  },
  modules: {
  }
})

state: 此处用于存储全局共享的状态数据,可以直接将数据定义在此处,全局可用:

state: {
    user: {name: 'zs'}
}

vue组件中使用:通过this.$store访问vuex的仓库:

let name = this.$store.state.user.name
<div>{{$store.state.user.name}}</div>

mapState辅助函数

<div>{{user.nickname}}</div>
<div>{{token}}</div>

import {mapState} from 'vuex'
export default {
    computed:{
        ...mapState(['user','token'])
    }
}

mutations: 用于提供一些方法,修改state中的状态数据:

mutations:{
    // 这个方法完全被vuex所管理,由vuex来调用,参数由vuex来传递
    // vuex将会传过来两个参数:
    //   state: 当前vuex仓库的state对象
    //   newName: 形参,由用户指定,vuex将会把用户的参数也带过来赋值给newName
    updateName(state, newUser){
        state.user = newUser
    }
}

mutations中的方法定义完成后,用户可以通过以下代码来调用这个方法,从而修改state中的数据:

// commit方法用于通知vuex:“vuex,请你执行updateName方法,顺便给你传个参数”
// this.$store.commit('mutations方法名称', 自定义参数信息)
this.$store.commit('updateName', {id:1, user:'温柔的亮', email:'xxx'})

mapMutations辅助函数

import {mapMutations} from 'vuex'
export default {
    methods: {
        ...mapMutations(['updateUserInfo', 'saveToken'])
    }
    mounted(){
        this.updateUserInfo(user)  代替
        this.$store.commit('updateUserInfo', user)
    }
}

actions: actions: 用于提供一些方法,异步做了一些耗时任务后,修改state中的状态数据 , (不能直接修改state,而是需要调用mutations中的方法,来修改state)。

actions: {
    // 这个方法完全被vuex所管理,由vuex来调用,参数由vuex来传递
    // vuex将会传过来两个参数:
    //   store: 当前vuex仓库Store对象
    //   payload: 形参,由用户指定,vuex将会把用户的参数也带过来赋值给payload
    login(store, payload){
      // 执行异步任务,发送请求,得到结果后
      // 将异步任务的结果交给mutations来进行后续处理
      // store.commit('updateUserInfo', 用户对象)
    }
},

如何调用actions的方法呢?

// this.$store.dispatch('actions中的方法名称', 用户自定义的参数)
this.$store.dispatch('login', {username:'zs', password:'123456'})

mapActions辅助函数

import {mapActions} from 'vuex'
export default {
    methods: {
        ...mapActions(['login'])
        login(user){
    		this.$store.dispatch('login', user)
		}
    }
    mounted(){
        this.login(user)  代替
        this.$store.dispatch('login', user)
    }
}
只有登录后,才可以看到除登录之外的页面。

实现思路:在项目的VueRouter对象中添加前置守卫,前置守卫将会在跳转路由页面之前先执行,我们就可以在此处判断,用户访问当前地址时,vuex里是否有当前用户,如果有可以通过,如果没有,直接拦截后,强制跳转到登陆页面。

只有登录后,才可以发送登录请求之外的http的请求

如果想要实现该功能,则需要服务端进行请求验证,验证当前请求中是否包含登录用户的身份(服务端需要完成用户身份的鉴权),如果该用户拥有操作数据的权限,则执行相应业务;如果该用户没有处理该请求的权限,则直接打回去,返回一个错误消息:您没有操作该模块的权限。

基于Token机制重构所有的请求
  1. 当发送登录请求,得到响应后,不仅可以获取到当前登录用户,还可以获取到一个服务端返回回来的Token加密字符串。这个字符串客户端看不懂,由服务端生成,在该Token字符串中,包含了很多与用户相关的信息:userId nickname email phone 过期时间等信息。
  2. 客户端获取该token字符串后,需要将token存起来,当做是当前用户的身份标识符,以后发送任何的请求时,都要携带该token字符串一起发送请求。
  3. 这样服务端就可以接收该请求,解析出token后进行解密,解密出用户信息,从而了解该请求是哪一个用户发出的,完成用户鉴权后实现后续业务。

TypeScript

TypescriptJavascript的一个超集。 Typescript在原有js的基础之上又添加了编译期的类型检查的功能,意味着在TS的环境下进行开发时,会对数据类型进行较为严格的验证,防止程序员写出可能出错的代码。规范编程习惯,适合大型项目开发使用。

Vue3.x

TypeScript代码的编写及运行方式

typescript代码写在后缀名为.ts的文件中,这种文件可以被typescript编译器编译解析,最终生成一套功能相同的js代码,输出到一个.js文件中。typescript语言的类型语法的验证都是在编译期间来处理的。生成出来的js与普通的js并无差别。

如果在编译的过程中,ts语法有类型验证错误,则会中断编译,报错。

全局安装Typescript编译器

npm install -g typescript   # 安装ts编译器
npm install -g ts-node    # 安装ts-node后,可以使用code runner执行ts文件
npm install @types/node  

安装成功之后,就可以使用tsc命令,对ts文件进行编译:

tsc helloworld.ts

编译过程做类型检查,通过后,将生成helloworld.js文件,项目中使用的依然是js文件。

vscode中有个插件可以使用:

code Runner

Typescript的数据类型

https://www.tslang.cn/docs/handbook/basic-types.html

// 01_basictype.ts  基本数据类型
// 描述一个人
let lName:string = '亮亮';
let lAge:number = 28;
let lMarried:boolean = true;

// let lHobby: string[] = ['摊煎饼', '玩单杠', '擦玻璃']
let lHobby: Array<string> = ['摊煎饼', '玩单杠', '擦玻璃']

// 亮亮的玩具 Tuple类型
// 描述一个3阶 边长10公分 的 塑料魔方
let mofang:[number,number,string] = [3, 10, '塑料']

// 枚举类型
// 枚举类型的作用就是用一个友好的名称来引用一些变量值
let c1 = '#ff0000'  // 红色
let c2 = '#00ff00'  // 绿色
let c3 = '#0000ff'  // 蓝色
let css = `background: ${c1}, color: ${c2}`
// 使用枚举类型,定义这些颜色值,每一个颜色指定一个友好的名称
enum Color {Red='#f00', Green='#0f0', Blue='#00f'}
// 上述枚举类型Color定义完毕后,意味着在Color中有3个可以选择
// 的枚举值,使用时,通过Color.的方式直接引用,有提示
css = `background:${Color.Red}; color:${Color.Blue}`
console.log(css)

enum BMDURL {  //通过枚举 给不好记的地址,起一个好认的名字
    ADD_ACTOR = '/actor/add',
    UPDATE_ACTOR = '/actor/update',
    ADD_MOVIE = '/movie/add',
    ADD_CINEMA = '/cinema/add'
}
//经常会使用枚举类型,定义大量的常量值,通过友好的名称方便访问
let url1 = 'http://localhost:8080' + BMDURL.ADD_ACTOR
let url2 = 'http://localhost:8080' + BMDURL.UPDATE_ACTOR
let url3 = 'http://localhost:8080' + BMDURL.ADD_MOVIE
let url4 = 'http://localhost:8080' + BMDURL.ADD_CINEMA
// .....
enum Sex {FAMALE, MALE} // 女性=0   男性=1
enum Category {Hot, Wait, Classic} // 热映0 待映1 经典2
console.log(Category.Hot)
console.log(Category.Wait)
console.log(Category.Classic)

// Any类型
//有时,会想要为那些在编程阶段还不清楚类型的变量指定一个类型。 
// 这些值可能来自于动态的内容,比如来自用户输入或第三方代码库。
// 这种情况下,我们不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。 那么我们可以使用 any类型来标记这些变量:

//假设res就是axios返回的结果
let res:any = {code:200, msg:'ok', data:[]}
console.log(res)
res = {code:401, msg:'token已经失效'}
console.log(res)

// 类型断言 
// 定义一个变量v1,但是不太清楚具体存储的数据类型,所以:any
let v1:any = '/home/user/login'
// 调用v1.split()方法时,不会有提示,因为vscode不知道v1是什么
let r1 = v1.split('/')
// 在此处,如果认为确定v1就是字符串类型,那么可以做:类型断言
// <string>: 类型断言 
// 告诉ts编译器:放心,我断定v1就是字符串,当字符串用即可
let v2:string = <string>v1
console.log(v2.split('/'))  // split方法就有提示了

Typescript中的函数

和JavaScript一样,TypeScript函数可以创建有名字的函数和匿名函数。 你可以随意选择适合应用程序的方式,不论是定义一系列API函数还是只使用一次的函数。

函数的类型

Typescript中函数的声明语法中可以指定函数返回值的类型:

function add(x: number, y: number): number {
    return x + y;
}

let myAdd = function(x: number, y: number): number { return x + y; };

如上述指定函数参数的类型与返回值的类型后,调用函数时就必须遵守函数的参数的类型定义,必须传递两个number,得到一个number

// 02_func.ts

// 声明一个函数,得到一个n以内的小数(随机数)
function getNum(n :number) :number{
    return Math.random() * n
}
let r = getNum(10)
console.log(r.toFixed(2))

// 为变量指定类型:完整函数类型的定义
// myadd是一个函数,该函数必须接受两个number参数,返回number
let myadd: (x:number, y:number)=>number = 
    function(x:number, y:number):number{ return x+y }
console.log(myadd(10, 10))
// console.log(myadd(10, '1'))  // 错误参数对不上

// 调用ts的函数时,参数列表必须与ts函数的参数列表的定义一一对应
function buildName(fname:string, lname?:string):string{
    return `${fname} - ${lname}`
}
console.log(buildName('成','小亮'))
console.log(buildName('纪','小新'))
// 如果有需求,可能传一个,也可能传两个参  【?: 可选参数】
console.log(buildName('纪'))   // 

// 定义一个函数,传递pagesize与page变量,返回分页查询结果
function queryList(pagesize:number = 20, page:number = 1){
    return `返回第${page}页的数据。(每页${pagesize}条)`
}
console.log(queryList(10))
console.log(queryList(10, 3))
// 什么都不传,应该返回默认page=1  pagesize=20
console.log(queryList())

Typescript中的自定义类型

// Person.ts
// 声明一个自定义类型,用于描述一个人
// 自定义类型中需要定义一些属性字段用于更精确的描述一个人
class Person {
    name: string;   // 属性    【类的成员】
    age?: number;    // 属性
    married?: boolean;  // 属性
    // 构造器【类的成员】new时执行 用于构造一个具体的对象
    constructor(name:string,age?:number,married?:boolean){
        this.name = name
        this.age = age
        this.married = married
    }
    // 【类的成员】 方法  向某人打招呼
    greet(other?: Person){
        if(other){
            console.log(
                `${this.name}正在向${other.name}打招呼`)
        }else{
            console.log(`${this.name}正在打招呼`)
        }
    }
}
//new通过自定义类型中声明的信息,创造一个人
let p1:Person = new Person('亮亮', 29, true);
//new通过自定义类型中声明的信息,创造一个人
let p2:Person = new Person('泡泡');
//new通过自定义类型中声明的信息,创造一个人
let p3:Person = new Person('小新', undefined, false);
console.log(p1.name)
console.log(p2.name)
console.log(p3.name)

// 调用对象的方法
p2.greet(p1)
p2.greet(p3)
p2.greet()  //  没有传递参数
enum Color {BLACK, BLUE}
enum Rom {G8, G16}
enum Store {G128, G256}

// Phone.ts  用于描述一台手机
class Phone {
    brand: string;  // 品牌
    name: string;  // 名称
    price: number; // 价格
    color: Color;  // 配色
    rom: Rom;   // 内存
    storage: Store; // 存储
    constructor(brand:string, name:string, price:number,
        color: Color, rom:Rom, storage:Store){
        this.brand = brand;
        this.name = name;
        this.price = price;
        this.color = color;
        this.rom = rom;
        this.storage = storage;
    }
}
// 造一部手机
let p1:Phone = new Phone(
    'Oppo', 'A36', 899.0, Color.BLACK, Rom.G16, Store.G128)
console.log(p1)
// 再造一部手机: Apple iPhone14pro Max 黑色 16G 256G  9.9元
let p2:Phone = new Phone(
    'Apple', 'iPhone14pro Max', 9.9, Color.BLACK, Rom.G16, Store.G256)
console.log(p2)
enum Color {BLACK, BLUE, RICE, WHITE, GRAY}
// Shoes.ts  实体类的定义
class Shoes {
    title: string;
    price: number;
    brand: string;
    color: Color;
    size: number;
    constructor(title:string, price:number, brand:string,
        color:Color, size:number){
        this.title = title;
        this.price = price;
        this.brand = brand;
        this.color = color;
        this.size = size;
    }
}

作业:做一个扑克牌比大小的小游戏。

提示:

  1. 需要设计一些实体类:

    class Card {
        suit花色 黑红梅方
        rank点数 3,4,5,6,7,8,9,10,J,Q,K,A,2,小,大
        
        compare(other:Card):number{
            返回-1 比other小
            返回1  比other大
        }
    }
    class Player {
        name名字
      	cards: Card[]
      	mopai(card){}
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值