通俗易懂vue笔记

1. Promise** 对象 ** 用于表示一个异步操作**的最终完成 (或失败)及其结果值。
  1. 是一个构造函数,异步编程的一种解决方案
  2. 通过其所带函数then 这个异步任务(函数)执行完成之后被执行
  3. 拥有resolve 成功返回,reject失败返回 两个回调函数 链式操作
  4. catch 其实它和then的第二个参数一样,用来指定reject的回调 ;
  5. all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调
  6. race all方法的效果实际上是「谁跑的慢,以谁为准执行回调」,那么相对的就有另一个方法「谁跑的快,以谁为准执行回调」

​ ##vue-tsc 是对 vue 3 的一个类型检测工具

2. reactive() 与 ref()
基本语法:创建响应式数据对象,等价于 vue 2.x 中的 Vue.observable() 函数
  • reactive 和 ref 都是用来定义响应式数据的 reactive更推荐去定义复杂的数据类型 ref 更推荐定义基本类型

  • ref 和 reactive 本质我们可以简单地理解为ref是对reactive的二次包装, ref定义的数据访问的时候要多一个.value

  • 使用ref定义基本数据类型,ref也可以定义数组和对象。

 1.isRef() 用来判断某个值是否为 ref() 创建出来的对象。
 2.toRefs() 函数可以将 reactive() 创建出来的响应式对象,转换为普通的对象,只不过,这个对象上的每个属性节点,都是 ref() 类型的响应式数据。
3. provide 与 inject 和 InjectionKey
provide() 和 inject() 可以实现嵌套组件之间的数据传递。这两个函数只能在 setup() 函数中使用。父级组件中使用 provide() 函数向下传递数据;子级组件中使用 inject() 获取上层传递过来的数据。

用provide和inject可以很方便的在父子组件之间通讯,即使是多层子组件,也能获取到父组件的值。但是会遇上类型上的问题,导致父组件传给子组件的方法无法调用,这时候我们可以使用vue3提供的InjectionKey解决这一问题

在父组件中定义对象和函数 ,用provide暴露

const user = ref({ name: 'Karen', age: 20 })
provide('user', user)
 
const setUser = ({ name, age }: { name: string; age: number }) => {
  user.value.name = name
  user.value.age = age
}
provide('setUser', setUser)

子组件用inject接收

const user = inject('user')
const setUser = inject('setUser') // 报错 const setUser: unknown 

可以看到接收到的对象和函数都是unknown,导致函数无法调用

这时候就有用到InjectionKey来定义类型,确保父传出去的值和子接收到的值类型是一样的

定义InjectionKey

import { InjectionKey, Ref } from 'vue'
 
export interface User {
  name: string
  age: number
}
 
export type SetUser = (newUser: User) => void
 
// 对象的InjectionKey
export const userKey: InjectionKey<Ref<User>> = Symbol('')
 
// 函数的的InjectionKey
export const setUserKey: InjectionKey<SetUser> = Symbol('')

接下来provide和inject就不要用字符串来定义名称了,用定义好的InjectionKey

父组件

import { userKey, setUserKey } from './type'
 
const user = ref({ name: 'Karen', age: 20 })
provide(userKey, user)
 
const setUser = ({ name, age }: { name: string; age: number }) => {
  user.value.name = name
  user.value.age = age
}
provide(setUserKey, setUser)

子组件

const user = inject('user')
const setUser = inject('setUser') 
setUser?.(...)

可以看到,子组件这里接收到的值和函数都拥有了类型,函数也能正常调用了

4. 什么是数据响应式

即数据双向绑定,改变Model时,View自动更新。改变View时,Model也会自动更新。

数据响应式原理
在Vue2.x版本中,利用Object.defineProperty()重新定义对象获取属性值(get)和设置属性值的操作实现数据响应。
在Vue3.0版本中,采用ES6的Proxy对象来实现。

5. vue 挂载周期

可以理解为有一堆描述dom的数据需要整理(虚拟dom,其实就是一堆对象储存了一堆数据),然后这些数据用js的API,比如createElement,创造出dom,这个过程是挂载前的动作。 创造出的dom还没有被使用,仅仅在内存中,需要“挂载”,然后你最外层是不是有一个叫app的id的dom?然后挂载就是document.querySelector(‘app’).appendChild(dom),就完成挂载啦

通俗易懂vue笔记_第1张图片

6. … 是扩展运算符。

扩展语法。对数组和对象而言,就是将运算符后面的变量里东西每一项拆下来。
这个东西可以在函数定义的地方使用,比如使用func(…args)将函数传入的参数都放到args数组里。

7. $$与||运算符

&& 表示为真时 执行
|| 表示为假时 执行

8. 过滤器 “|” 管道符

过滤器函数接受表达式的值作为第一个参数。

以下实例对输入的字符串第一个字母转为大写:

{{ message | capitalize }}

过滤器可以串联:

{{ message | filterA | filterB }}

过滤器是 JavaScript 函数,因此可以接受参数:

{{ message | filterA('arg1', arg2) }}
9. **? .和? ?**运算符

?. 可选链操作符

const obj = {}
// console.log(obj.msg.info) // 这句会报错,不信你试试
console.log(obj && obj.msg && obj.msg.info)
console.log(obj ?. msg ?. info)
// 读取对象深处的属性的值,而不必明确验证链中的每个引用是否有效, 如果深层没有该值你还使用.读取会报错

?? 空值合并操作符

// 使用?? 运算符
  console.log(null ?? 1) // 1
  console.log(undefined ?? 2) // 2
  console.log(0 ?? 3) // 0
  console.log(false ?? 4) // false
  console.log("" ?? 1) // ""
  // 使用|| 运算符
  console.log(null || 1) // 1
  console.log(undefined || 2) // 2
  console.log(0 || 3) // 3
  console.log(false || 4) // 4
  console.log("" || 5) // 5
  // 使用?? 当左侧的操作数为 null 或者 undefined,使用的是后面的数据,其他的皆使用运算符前面的数据
  // 使用|| 当左侧的操作数为真就使用的是前面的数据,为假就使用的是后面的数据

10.箭头函数=>

  var f = a =>a
  //等同于
  var f=function(a){
  return a;
  }

如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。

// 无行参
var f=()=>5;
var f =function(){
return 5;
}
//多个行参
var sum = (num1,num2)=>num1+num2;
var sum = function (num1,num2){
 return num1+num2;
}
// 一个参数
  var f = a =>a
  //等同于
  var f=function(a){
  return a;
  }

使用箭头函数注意事项

1.函数体内的this对象,就是定义时所在的对象,而不是使用时的对象。

10. TypeScript 之 Record

在 TS 中,类似数组、字符串、数组、接口这些常见的类型都非常常见,但是如果要定义一个对象的 key 和 value 类型该怎么做呢?这时候就需要用到 TS 的 Record 了

很好理解,Record 后面的泛型就是对象键和值的类型。

比如我需要一个对象,有 ABC 三个属性,属性的值必须是数字,那么就这么写:

type keys = 'A' | 'B' | 'C'
const result: Record = {
  A: 1,
  B: 2,
  C: 3
}
11. ts 数据类型

ts数据类型 分原始类型对象类型

原始类型 7种

  • boolean

  • Null

  • Undefined

  • Number

  • BigInt

  • string

  • Symbol (符合类型)

    symbol

    1.新增的第7种数据类型,表示独一无二,用来做属性名,能保证不会与其他的属性名冲突
    2.他是通过Symbol函数生成的
    3.他的前面不能用new,因为它生成的是一个原始类型的数据,不是对象
    4.它可以接受一个参数,为了便于区别,即使长得一样也不相同
    5.它不能与其他的值进行运算,没有隐式转换
    6.它的值可以转换成布尔值或者字符串,不能转化为数字

    
    
     
    
    
        
        
    
    
    
           
    
    
    

    any 类型

    假如说现在有这样一个需求, 我们可能要一个第三方系统, 系统输入的值是什么类型,我们不知道,不输入我门无法知道它们是什么类型 ,这个时候我们可以使用 Any 类型 ,意思是 允许赋值为任意类型 ,代码如下

// 允许赋值为任意类型
let notSure:any = 4

// 赋值成 string 类型
notSure = 'maybe a string'

// 赋值成 boolean 类型
notSure = true

// 调用属性以及方法也不会报错
notSure.myName
notSure.getName()
12. 数组与元祖
数组

Typescript 中,我们可以这样定义 值都为 number 的数组 ,如下:

// number 类型数组,数组项不可以出现非 number 类型之外类型的数据
let arrOfNumbers:number[] = [1, 2, 3]

// 数组的方法对数组进行添加数据时也必须为 number 类型
arrOfNumbers.push(3)

function test(){
    // arguments 是一个类数组
    console.log(arguments)
    // 不可以像下面这样写,因为类数组跟数组是不一样的,它缺少数组的方法
    let arr:any[] = arguments
}

如果是 数组对象 的数据结构,可以使用 接口(interface)约束数组对象 ,代码如下:

interface IDataType {
    name: string,
    age?: number
}


let data:IDataType[] = [
    {
        name: '小明'
    },
    {
        name: '小芳',
        age: 18
    },
]
元祖

数组同一个类型的数据集合 到一起,例如我们上面的例子,数组的值 ,都是 number类型 的,那么 加入不同类型的数组的值 怎么办,大家可能会想到用 array:any[] ,但是 any[] 就会 丧失具体的类型 ,这不是我们想要的,我有很明确的目标,比如:我数组的第 1 个值是 number,第二个值是 string ,这时候我们可以使用 元祖元祖合并了不同类型的对象元祖 起源于 函数式编程 ,如果对 python 有过了解的人可能会有了解

// 定义元祖
let user: [string, number] = ['viking', 20]

// 可以向元祖中push数据
user.push('true')
13. Interface** -接口

Interface 可以定义 object 类型数据Interface 也称之为 Duck Typing(鸭子类型)Interface 非常灵活, 可以描述编程语言的各种类型Interface 不存在 javascript 的概念,所以 ts 在编译以后,Interface 是不会被转换到 js 文件中的,所以 它(Interface)只能用来做类型的静态检查

  1. 接口用法

    // 定义接口
    interface Iperson {
        name: string;
        age: number;
    }
    
    // 定义变量
    let viking: Iperson = {
        name: 'viking',
        age: 18
    }
    

    有的 编程语言建议 interface 名称定义时,第 1 个字母用大写 I , 意思是告诉大家这是一个 interface ,上面的意思是 定义一个接口,然后 viking 这个变量用定义好的 Iperson 这个接口的规则,来约束这个变量,需要注意:如果 viking 变量中少属性或多属性会报错,给变量赋值时形状保持与接口一致 这种情况该怎么办呢,可以使用可选属性

  2. 可选属性

    可选属性该属性可以是不存在的 ,像下面这样写 age 就是可选可不选的

    // 定义一个接口
    interface Iperson {
        name: string;
        age?: number;
    }
    
    // 定义一个变量
    let viking: Iperson = {
        name: 'viking',
        // age: 20
    }
    
  3. 自读属性

    有时候我们希望 对象中的一些属性只能被赋值,后期只能读取,不能修改 ,我们可以用 readonly , 这样写

    // 定义一个接口
    interface Iperson {
        readonly id:number;
        name: string;
        age?: number;
    }
    
    // 定义一个变量
    let viking: Iperson = {
        id: 1,
        name: 'viking',
        age: 20
    }
    
    // 修改 id 就会报错
    viking.id = 9527
    

readonlyconst关键字 有点相似,它们之间的区别是 readonly 是用在属性上的 ,而 const 是用在变量上的

14. 声明变量、变量、变量类型
let        name: string='张三'
 ↑          ↑      ↑
 声明变量    变量   变量类型

声明变量:要想使用变量,你需要做的第一步就是创建它 – 更准确的说,是声明一个变量。声明一个变量的语法是在 varlet 关键字之后加上这个变量的名字

变量: 变量是用来存储数值的,那么有一个重要的概念需要区分。变量不是数值本身,它们仅仅是一个用于存储数值的容器。你可以把变量想象成一个个用来装东西的纸箱子

变量类型:string、number、boolean…

15. var、let、const 区别

var和let的区别

  1. 全局环境声明的区别

    在全局环境中声明变量,var和let的主要区别在于,var声明的变量会成为window的属性或方法,而let则不会

var num1 = 1;
let num2 = 2;
console.log(window.num1,window.num2);
输出:1 undefined
  1. 变量提示

    使用var 声明变量时变量会提升,let不会

console.log(num);
var num = 1;
输出:undefined
等价于:
var num;
console.log(num);
num = 1;

变量声明提升

console.log(test);
let test = "js";
报错:Uncaught ReferenceError: test is not defined
    at <anonymous>:1:13

var声明的变量是函数作用域,而let声明的时块级作用域

function fun(){
    for(var i = 0;i < 10; i++){
    }
    console.log(i);
}
fun();
输出:10
function fun(){
    for(let j = 0;j < 10; j++){
    }
    console.log(j);
}
fun();
报错:VM808:4 Uncaught ReferenceError: j is not defined
    at fun (<anonymous>:4:17)
    at <anonymous>:6:1

第二个之所以会报错,是因为let 声明的变量是块级作用域,只在相应的区块内有效,离开就没有访问权限,可以简单的理解{}就是一个区块,第二个函数的for循环是一个区块,j在下面输出的时候,离开for循环这个块级作用域,所以会报错。
const
const几乎和let差不多,唯一的区别是const声明的是常量,即一但赋值,值就不可以改变,否则会报错。它同样具有的是块级作用域

const num = 1;
num = 2;
报错:VM159:2 Uncaught TypeError: Assignment to constant variable.
    at <anonymous>:2:5
16.vue h函数

``ts
function fun(){
for(let j = 0;j < 10; j++){
}
console.log(j);
}
fun();
报错:VM808:4 Uncaught ReferenceError: j is not defined
at fun (:4:17)
at :6:1


第二个之所以会报错,是因为let 声明的变量是块级作用域,只在相应的区块内有效,离开就没有访问权限,可以简单的理解{}就是一个区块,第二个函数的for循环是一个区块,j在下面输出的时候,离开for循环这个块级作用域,所以会报错。
const
const几乎和let差不多,唯一的区别是const声明的是常量,即一但赋值,值就不可以改变,否则会报错。它同样具有的是块级作用域

```ts
const num = 1;
num = 2;
报错:VM159:2 Uncaught TypeError: Assignment to constant variable.
    at :2:5
16.vue h函数

h函数就是vue中的createElement方法,这个函数作用就是创建虚拟dom,追踪dom变化的

你可能感兴趣的:(vue,ts,前端)