vue3 初体验
vue3的更新是颠覆式的,最大的改变就是组合式api,以及shake tree优化代码运行速度,新的响应式原理,封装更多内置方法。
vue 3.0
- Vue -cli
- Vue -router
- VueX
Vue3 不需要根节点(在模板template)
vue setup
//新的optioon 所有的api都在次使用,只在初始化执行一次
//组合APi中第一个要使用的函数
Vue3 支持 vue2 大多数语法
1 | data(){ |
1)setup 是组合 api 的入口函数
Vue3 的写法
1 | setup(){ |
引入ref解决
1 | import { ref } from 'Vue' |
2)ref 定义一个响应式的数据
1 | //count未ref类型 |
3)reactive
1 | // |
reactive
1 | //作用:定义多个数据的响应式 |
1 | //对比两种情况下,数据的更新 |
补充:
需要注意的是,reactive
中传递的参数必须是json
对象或者数组,如果传递了其他对象(比如new Date()
),在默认情况下修改对象,界面不会自动更新,如果也需要具有响应式,可以通过重新赋值的方式实现
1 | //msg 的数据是存在变化的,但界面并未发生变化,同时我们发现在控制台里,msg 并未被识别成 proxy。 |
基本数据传递给reactive,reactive并不会将它包装成porxy对象,并且当数据变化时,界面也不会变化
4)比较Vue2与Vue3的响应式
vue2
核心
对象:通过defineProperty对对象的已有属性值的读取和修改进行劫持(监视/拦截)
数组:通过重写数组更新数组一系列更新元素的方法来实现元素修改的劫持
vue 3.0
通过proxy代理,reflect(反射对象),不是函数对象,不能构造
1 | //将目标对象变成代理对象 |
通过代理对象修改目标对象的值
通过代理对象向目标对象中添加一个新的属性
vue3的深度响应可以深度响应
5)setup 细节
1 | //父子组件通信 |
setup一般都是返回一个对象,对象中的属性和方法都可以在html模板中直接使用
1 | setup是在beforeCreate生命周期之前就执行了,而且就执行一次 |
setup运行的时机
setup执行的时机
- 在beforeCreate之前执行(一次),此时组件对象还没有创建,不能使用data和methods
- this是underfinded,不能通过this来访问data/computed/methods/props
- 其实所有的composition API 相关回调函数中也都不可以
setup的返回值
- 一般都返回一个对象,为模板提供数据,也就是模板中可以直接使用次对象中的所有属性方法
- 返回对象中的属性会与data函数返回对象的属性合并并成为组件对象的属性
- 返回对象中的方法会与methods中的方法合并并成功组件对象的方法
- 如果有重名,setup优先
- 注意
- 一般不要混合使用,methods和data都可以写在setup
- setup不能是async函数,因为返回值不再是一个对象,而是一个promise,模板看不到对象中的属性数据
- 数据初始化的生命周期回调
setup()的参数
两种写法
1.setup(props,contect)
2.setup(props,attrs,slots,emit)
props 参数,是一个对象,里面有父级组件向子级组件传递的数据
contect参数(是一个对象)
```js
1.attrs
//获取当前组件标签的属性,但是该数据是在props中,没有接收的所有的属性的对象
2.emit
//分发事件
@xxx = ‘xxx’
function xxx(txt){
msg.value += txt;
}
<button @click=’emitXXX’>分发事件
function emitXXX(){
context.emit(‘xxx’,’+’)
}
3.expose
4.slots
//插槽1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
## 6)ref和reactive细节(响应式API)
- ref也可以传递对象吗
1. 如果ref里面传递的是对象/数组,那么是经过了reactivity处理,形成了Proxy类型的对象,
2. ref内部:通过给value属性添加getter/setter来实现对数据的劫持
3. reactivity内部:通过使用Proxy来实现对对象内部所有的数据的劫持,并通过Reflect操作对象内部数据
4. ref的数据操作,在js中要.value,在模板中不需要,(内部解析模块会自动添加.value)
**递归监听和非递归监听**
`ref`和`reactive`都属于递归监听,也就是数据的每一层都是响应式的,如果数据量比较大,非常消耗性能,非递归监听只会监听数据的第一层。
*** 数组也使用**reactive**
## 7)计算属性与监视
1. 计算属性
```js
import { ref } from "@vue/reactivity";
import { computed } from '@vue/runtime-core';
export default {
name: "detailforref",
setup() {
const m1 =ref("东方");
const m2 = ref('不败')
const all = computed(()=>{
return m1.value + m2.value
})
const updataname = () =>{
m1.value = '西方'
m2.value = '求败'
}
return {
m1,
m2,
all,
updataname,
}
},
};- 计算属性中如果只传入一个回调函数,表示的是get
- 计算属性返回的是一个ref类型的对象
监视属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29import { ref } from "@vue/reactivity";
import { watch } from '@vue/runtime-core';
export default {
name: "detailforref",
setup() {
const m1 =ref("东方");
const m2 = ref('不败')
const user = [m1,m2]
const all = ref('')
// const all = computed(()=>{
// return m1.value + '_' + m2.value
// })
watch(user,(val)=>{
return all.value = val[0]+'__'+val[1]
})
const updataname = () =>{
m1.value = '西方'
m2.value = '求败'
}
return {
m1,
m2,
all,
updataname,
user
}
},
};
- 不会默认调用,需要手动配置默认调用
1 | immediate:true |
- watchEffect()
1 | //监视,不需要配置immediate,本身默认就会进行监视,(默认执行一次) |
- watch可以监视多个数据
1 | watch([user.firstName,user.lastName,Fullnsmes3],()=>{ |
8)生命周期对比
1 | beforeCreate() |
3.0里面的生命周期钩子比2.0生命周期快
9)自定义hook函数
类似于mixin
//公共接口是否可以混入组件或者临时存储
1 | import {ref} from "@vue/reactivity"; |
1 | import {defineComponent} from 'vue' |
https://juejin.cn/post/6977929393511514148
1. ref和shallowRef
ref
定义的数据每一层都是响应式数据shallowRef
定义的数据,只有第一层是响应式的,即只有在更改.value
的时候才能实现响应式
2.toRaw
toRaw的出现是解决什么问题呢?
有些时候我们不希望数据进行响应式实时更新,可以通过toRaw
获取ref
或reactive
引用的原始数据,通过修改原始数据,不会造成界面的更新,只有通过修改ref
和reactive
包装后的数据时才会发生界面响应式变化。
1 | let obj1 = {...}; |
3.markRow
与toRaw不同,markRaw包装后的数据永远不会被追踪!
暂时没发现有什么用处(手动狗头)
1 | let obj1 = {name: "lijing", age: 18} |
toRef和toRefs
1)ref
1 | 使用ref对一个对象的某个简单数据类型属性进行响应式改造后,通过修改响应式数据不会影响到原始数据,如上图中,通过state1修改值后,obj1中的a属性值没有发生变化。这里有个注意点:修改的这个属性必须是简单数据类型,一个具体的值,不能是引用,如果该属性也是一个对象,则会影响,因为对象--->引用! |
2)ref的另一个作用
1 | <button ref='inoutref'></input> |
2. toRef
为源响应式对象上的某个属性创建一个ref对象,二者内部操作的是同一个数据值,更新时二者的是同一个数据值,更新时二者是同步的
- 区别ref:拷贝了一份新的数值单独操作,更新时互不影响,toRef两个数据之间有关联
- 应用:当要将某个prop的ref传递给复合函数时,toRef很有用
- 原本时传递普通数据,若使用toRef则传递的是ref对象
如果使用toRef来转换,则修改响应式数据会影响到原始数据,数据发生改变,但是界面不会自动更新
转换后的是一个ObjectRefImpl
类型
3. toRefs
将一个响应式对象转换为普通对象,该普通对象 的每一个property都是一个ref
1 | const state1 =toRefs(state) |
遍历对象中的所有属性,将其变为响应式数据,这是因为toRef
只能传一个key
,toRefs
所达到的效果与toRef
一样
10)shallowReactive 和 shallowRef
1.reactive 为深度响应式
2.shallowReactive 浅响应式
3.ref为深度响应式
4.shallowRef为浅响应式
shallowRef 只进行value的响应式,不进行对象的reactive处理
1 | //什么时候用浅响应式 |
11)readonly和shallowReadonly
深度可读和浅度可读
12)toRow 和 markRow
toRow ->将代理对象变为普通对象
markRow ->标记的对象数据从此以后不能再成为代理对象
13)customRef 自定义ref
可以用于自定义一个ref,可以显式的控制依赖追踪和触发响应,接受一个工厂函数,两个参数分别是用于追踪track 与用于触发响应的trigger,并返回一个带有get 和 set 属性的对象,
- 使用自定义ref实现带防抖功能的v-model
track trigger 延申知识
14)inject和provide
依赖注入,实现跨层级,祖孙之间数据传递
1 | provide('color',color) |
15) 判断数据
- isRef:检查一个值是否为一个ref对象
- isReactive:检查一个对象是否有reactive创建的响应式数据
- isReadonly:检查一个对象是否由Readonly创建的只读代理
- isProxy:检查一个对象是否由reactive或者Readonly创建的代理
16)新组件
- Fragment(片段)
- 在vue2中必须有一个根标签
- 不需要根标签,减少标签层级,减小内存占用
- Teleport(瞬移)
1 | <Teleport to=''><Teleport> |
将该标签内的。。。
待补充
Suspence(不确定的)
运行在渲染异步组件时渲染一些后背内容,可以让我们创建一个平滑的用户体验
vue2动态引用组件
1 | const component =()=>import './...' |
vue3 动态引入组件
1 | import {defineAsyncComponent} from 'vue' |
Suspence使用
1 | <Suspence> |
Vue2 给原型挂载方法
vue3 给原型挂载方法
Vue3 面试
抱歉:研究没有那么深
2020.9正式版->2022.2.7默认版本->Vue 3 支持vue2大多数特性 - > 新一代构建工具,按需编译,热加载更快 -> 不需要根节点 ,减少内存占用 -> 组合式api ,代替了Vue2,option api,复用性更好,更好的支持Ts -> 深度监视,之前需要set监视数组内部数据变换,现在直接就可以深度监视 -> suspence 更加注重用户体验 ->hook函数 -> 跨级组件通信 ,依赖注入 -> ref实现防抖 -> 可以使用2的生命周期函数,vue3的周期函数更快 -> 响应式数据原理Proxy -> 重写虚拟dom,速度更快 ->新组件瞬移,片段(不需要根节点)