升级v3是因为 v2有一些基础bug 例如数据丢失等 但是 v3就解决了这个问题 v3利用了双向数据绑定 数值变化页面就该变
v2 和 v3 的 api 不一样 v2的api是选择式的 v3是组合式的 例如 setup就是组合的
v2 和 v3 的生命周期也不太一样
v2 和 v3 的双向绑定也不太一样,v2采用的是object.definepropty()数据劫持订阅发布获取的 v3采用的是 proxy 数据代理
v3也没有this指向 如果需要的话 可以在 setup 进行定义
Vue2--------------vue3
beforeCreate -> setup()
created -> setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
activated -> onActivated
deactivated -> onDeactivated
errorCaptured -> onErrorCaptured
ref和reactive都是Vue.js 3.x版本中新增的响应式API,用于实现组件的数据响应式更新。它们的主要区别如下:
1. 数据类型不同:ref用于包装JavaScript基本类型的数据(如字符串、数字、布尔值等),而reactive可以用于包装JavaScript对象和数组等复杂类型的数据。
2. 使用方式不同:ref需要通过在模板中使用ref指令以及在JavaScript代码中使用ref函数进行创建和使用,而reactive则需要通过调用Vue.js提供的reactive函数进行包装和创建。
3. 访问方式不同:对于通过ref函数创建的响应式数据,我们可以通过.value属性来访问其实际值;而对于通过reactive函数创建的响应式对象,我们可以直接访问其属性或调用其方法。
4. 设计理念不同:ref主要是为了解决单一元素/数据的响应式问题,而reactive则是为了解决JavaScript对象和数组等复杂数据结构的响应式问题。总的来说,ref和reactive都是用于实现Vue.js组件的数据响应式更新,但是它们的使用方法、适用范围和设计理念等方面略有不同,需要根据具体的应用场景选择合适的API进行使用。
watch监听的三个属性
1.handler:watch中监听到数据变化后需要具体执行的方法;2.immediate:使用watch时有一个特点,就是当值第一次绑定时,不会执行监听函数,只有值发生改变时才会执行。如果我们需要在最初绑定值的时候也执行函数,则就需要用到immediate属性;
3.deep:当需要监听一个对象的改变时,普通的watch方法无法监听到对象内部属性的改变,此时就需要deep属性对对象进行深度监听,数组字符串一般不需要
data() {
return {
obj: {
'name': "王",
'age': 18
},
}
},
watch: {
obj: {
// 执行方法
handler(newValue,oldVal) {
console.log(oldValue)
console.log(newValue)
},
deep: true, // 深度监听
immediate: true // 第一次改变就执行
},
// 如果只需要监听对象中的一个属性值,则可以做以下优化:使用字符串的形式监听对象属性:
'obj.name': {
// 执行方法
handler(newValue,oldVal) {
console.log(oldValue)
console.log(newValue)
},
deep: true, // 深度监听
immediate: true // 第一次改变就执行
}
}
computed 是基于它的依赖缓存,只有在它的相关依赖发生改变时才会进行更新。官方文档是这样说的:对于任何包含响应式数据的复杂逻辑,你都应该使用计算属性
计算属性默认只有 getter,不过在需要时你也可以提供一个 setter:
计算属性和侦听器 — Vue.js (vuejs.org)
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
// ...
$emit,父组件传data给子组件,子组件通过$emit来触发父组件中绑定在子组件身上的事件,达到改变父组件中的data的方法。下面介绍$emit传值的几种方法
子组件
子组件
父组件
这是父组件
{{myString}}
深入理解和使用this.$refs——Vue.js的利器
Vue.js是一个流行的JavaScript框架,用于构建交互性强大的用户界面。在Vue.js中,this.$refs是一个强大的特性,允许你直接访问组件中的DOM元素或子组件实例。本教程将带你深入了解this.$refs的使用方法和场景。
什么是this.$refs?
this.$refs是Vue实例提供的属性,允许你访问组件中的DOM元素或子组件。这使得你能够在需要的时候直接操作DOM或与子组件进行通信,而不需要通过props或事件的方式进行交互。使用场景
访问DOM元素
有时候,你可能需要直接操作一个DOM元素,比如改变其样式、焦点等。使用this.$refs,你可以很方便地实现这些效果。
1.静态输入
静态类型化是一种功能,可以在进行编写脚本时检测错误。查找并修复错误,对于编写更健壮的代码并对其进行维护,以便使得代码质量更好、更清晰。2.大型的开发项目
有时为了改进开发项目,需要对代码库进行小的增量更改。这些小小的变化可能会产生严重的、意想不到的后果,因此有必要撤销这些变化。而使用TypeScript工具来进行重构更变的容易、快捷。3.更好的协作
当发开大型项目时,进行开发的过程当中乱码和错误的机也会增加。类型安全是一种在编码期间检测错误的功能,而不是在编译项目时检测错误。
双向映射是指在键值对中建立双向一一对应关系的一种模式。它既可以通过键名(key)去获取值(value),也可以通过值去获取键名。让我们看下如何在JavaScript中实现一个双向映射,以及 TypeScript 中的应用。
Typescript - enum 枚举类型(数值型枚举 / 字符串枚举 / 常量枚举 / 异构枚举 / 计算枚举成员 / 联合枚举和枚举成员类型 / 运行时的枚举 / 环境枚举 / 对象与枚举)教程_ts enum类型-CSDN博客
Enums(枚举)是 TypeScript 的少数功能之一,它不是 JavaScript 的类型级扩展,仅支持数字的和基于字符串的枚举。
在一个字符串枚举中,每个成员都必须用一个字符串字头或另一个字符串枚举成员进行常量初始化
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",
}
常量枚举通过在枚举上使用 const 修饰符来定义,常量枚举不同于常规的枚举,他们会在编译阶段被删除
const enum Size {
WIDTH = 10,
HEIGHT = 20
}
const area = Size.WIDTH * Size.HEIGHT; // 200
TS基础类型-CSDN博客
元组类型允许表示一个
已知元素数量和类型的数组
,各元素的类型不必相同。 比如,你可以定义一对值分别为string
和number
类型的元组。
//1.默认值
let tom: [string, number] = ['Tom', 25];
//2.通过下标赋值
let tom: [string, number] = ['', 0];
tom[0] = 'Tom';
tom[1] = 25;
//通过下标获取元组的元素并进行对应的操作
tom[0].slice(1);
tom[1].toFixed(2);
//3.越界操作
let tom: [string, number];
tom = ['Tom', 25];
tom.push('male');
tom.push(true);//报错,当添加越界的元素时,它的类型会被限制为元组中每个类型的联合类型
//解构赋值
const lilei: [string, number] = ["Lilei", 23];
console.log(lilei);
const [myname, myage]: [string, number] = lilei;
console.log(myname, myage);
// 解构赋值
let arr:[number,string]=[100,'hello']//不是解构
let [A,B]:[number,string]=[100,'hello']//是解构 ---->解构的隐式代码 let A=x[0] let B=x[1]
let obj1:[number,string]=[100,"hello"]
let [x,y]:[number,boolean]=[100,true]
console.log(x,y)
// 枚举
enum netWork{net2G,net3G,net4G,net5G,net6G}
function fn(x:number){
if(x==0){1
console.log("做2g的网络请求")
}
else if(x==1){
console.log("做3g的网络请求")
}
else if(x==2){
console.log("做4g的网络请求")
}
else if(x==3){
console.log("做5g的网络请求")
}
else if(x==4){
console.log("做6g的网络请求")
}
}
fn(netWork.net6G)//net6G-->可以需求改变
类型断言
有些情况下,变量的类型对于我们来说是很明确,但是TS编译器却并不清楚,此时,可以通过类型断言来告诉编译器变量的类型,断言有两种形式:
第一种
let someValue: unknown = "this is a string";
let strLength: number = (someValue as string).length;
1
2
第二种
let someValue: unknown = "this is a string";
let strLength: number = (someValue).length;
泛型(Generic)
定义一个函数或类时,有些情况下无法确定其中要使用的具体类型(返回值、参数、属性的类型不能确定),此时泛型便能够发挥作用。
举个例子:
function test(arg: any): any{
return arg;
}
1
2
3
上例中,test函数有一个参数类型不确定,但是能确定的时其返回值的类型和参数的类型是相同的,由于类型不确定所以参数和返回值均使用了any,但是很明显这样做是不合适的,首先使用any会关闭TS的类型检查,其次这样设置也不能体现出参数和返回值是相同的类型
使用泛型:
function test(arg: T): T{
return arg;
}
1
2
3
这里的就是泛型,T是我们给这个类型起的名字(不一定非叫T),设置泛型后即可在函数中使用T来表示该类型。所以泛型其实很好理解,就表示某个类型。
那么如何使用上边的函数呢?
方式一(直接使用):
test(10)
1
使用时可以直接传递参数使用,类型会由TS自动推断出来,但有时编译器无法自动推断时还需要使用下面的方式
方式二(指定类型):
test(10)
1
也可以在函数后手动指定泛型
可以同时指定多个泛型,泛型间使用逗号隔开:
function test(a: T, b: K): K{
return b;
}
test(10, "hello");
1
2
3
4
5
使用泛型时,完全可以将泛型当成是一个普通的类去使用
类中同样可以使用泛型:
class MyClass{
prop: T;
constructor(prop: T){
this.prop = prop;
}
}
1
2
3
4
5
6
7
除此之外,也可以对泛型的范围进行约束
interface MyInter{
length: number;
}
function test(arg: T): number{
return arg.length;
}
1
2
3
4
5
6
7
使用T extends MyInter表示泛型T必须是MyInter的子类,不一定非要使用接口类和抽象类同样适用。
正常是父子通信 如果 想祖孙通信 不像一个个传值 可以使用这个
provide/inject使用方式
provide:Object | () => Object inject:Array
| { [key: string]: string | Symbol | Object } provide:应该是一个对象或返回一个对象的函数。该对象包含可注入其子孙的 数据。在 该对象中你可以使用 ES2015 Symbols 作为 key,但是只在原生支持 Symbol 和 Reflect.ownKeys 的环境下可工作。 inejct:可以是字符串数组或者一个对象。接收到的值会被vue直接添加到当前组件实例对 象身上。 provide/inject的作用
vue官网原话【允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深, 并在其上下游关系成立的时间里始终生效。】也就是如果当前组件设置了provide传递数据, 那么在当前组件的所有后辈组件中,都可以使用inject接收这个数据。
this.$slots是vue里面的一个只读的api,用来访问被插槽分发的内容。每个具名插槽有其相应的 property (例如:v-slot:foo 中的内容将会在 vm.$slots.foo 中被找到)。default property 包括了所有没有被包含在具名插槽中的节点,或 v-slot:default 的内容。
这个api在日常用的不多,今天一个项目里控制列的展示中看到了这个api,然后惊奇的发现,在子组件的created里面打印this.$slots是一个空对象(请以JSON.parse(JSON.stringify())这种方式转换,因为对象后面会被赋值),在mounted里面打印才可以拿到。
这是因为在created阶段只是定义好了实例以及一些data,methods等基础属性,this.$slots这种属性只是进行了初始化定义,并没有真正赋值。而this.$slots其实会去寻找DOM元素对应的插槽,只有在mounted的阶段,DOM才被挂载成功。
js中的对象是由属性和方法构成的,而ts中对象的类型就是在描述对象的结构(有什么类型的属性和方法)
对象类型的写法:
const person:{name:string;age:number;sayHi():void}={
name:'XXX',
age: 18 ,
sayHi(){
//do something...
}
}
解释:
直接使用{}来描述对象结构 属性采用属性名:类型的形式 方法彩虹 方法名():返回值的形式
如果方法中有参数,就在方法名后面的小括号中指定参数类型 fn(name:string):void
再一行代码中指定对象的多个属性类型时,使用;分号来分隔
如果一行代码只指定一个属性类型(通过分割多个属性类型) 可以去掉;分号
方法的类型也可以使用箭头函数形式 ps {sayHi:()=>void}
参考
TS的常用类型_ts 可选类型-CSDN博客
函数的类型实际上指的是 函数参数和返回值的类型
为函数执行类型的两种方式:
//1指定参数 返回值的类型
function add(num1:number,num2:number):number{
return num1+num
}
const add=(num1:number,num2:number):number=>{
return num1+num
}
//2同时指定参数 和返回值的类型
const add:(arg1:number,arg2:number)=>number=(arg1,arg2)=>{arg1+arg2}
解释:当函数作为表达式时,可以通过类似煎肉函数形式的语法来作为函数添加类型
注意:这种形式 只适用于函数表达式
如果函数没有返回值,那么函数的返回值类型为 : void
function(name:string):void{
//do something....
}
可选参数:
是有函数实现某个功能时,参数可以传也可以不传.这种情况下,在给参数定义参数类型时就能用到
可选参数
ps:自己实现一个数组的slice方法 可以slice( 1 )也可slice( 1 , 3 )
可选参数:在可传可不传的参数名称后加?(问号)
注意:可选参数只能出现在参数列表的最后,也就是说也选参数后边不能再出现必选参数
//如果 数组中既有number类型 又有string类型:
类型别名(自定义类型):为任意类型起别名.
使用场景 当同一类类型(复杂)被多次使用时 可以通过类型别名,简化该类型的别名
const arr:(number|string)[]=[ 1 ,'a', 2 ,'b']
| 在ts中叫 联合类型 (由两个或者多个其他类型组成的类型表示可以是这些类型中的 任意一种)
//如果不添加括号 表示 既可以是数值类型也可以是字符串数组
参考
ts -- 交叉类型 · Typescript -- 学习 · 看云 (kancloud.cn)
1.交叉类型:我们可以把现有的多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性,取多个类型的并集 简单的说' 交叉类型是将多个类型合并为一个类型',用'&' 来表示 2.下面的案例是将两个对象合并,并且返回合并后的对象 3.仅仅把原始类型、字面量类型、函数类型等原子类型合并成交叉类型,是没有任何用处的,因为任何类型都不能满足同时 属于多种原子类型'比如既是 string 类型又是 number 类型'