Vue3简介
面临的问题:随着功能的增长,复杂组件的代码变得难以维护,Vue3
就随之而来,TypeScript
使用的越来越多,Vue3
就是 TS
写的所以能够更好的支持 TypeScript
在这里介绍就这么简单
vue2
的绝大多数的特性 在 Vue3
都能使用,毕竟 Vue
是渐进式的
响应式原理进行使用 Proxy
实现,v-model
可以传参了等等新特性
基础工作
使用Vue3
的话,那么必须通过使用构建工具创建一个 Vue3
项目
安装 vue-cli
创建一个项目
使用 create
命令行创建 或者 用 ui
可视化创建
大家用 Vue
都用了这么久,我就不一一说怎么去创建了
当然也可以选择 vite
,vite
创建的速度比 上面的方法快了一些
Vue3入门
Composition API
Vue3
提出了Composition API
在 Vue2.X 我们使用的是 OptionAPI 里面有我们熟悉的 data
、computed
、methods
、watch
...
在 Vue3
中,我们依旧可以使用 OptionAPI当然不建议 和 Vue3
混用
在 Vue2
中,我们实现一个功能得分到不同的地方,把数据放在 data
,computed
方法放在 methods
里面,分开的太散乱了,几个功能还好,几十个上百个,那就有点...
所以 Vue3
提出了 Composition API ,它可以把 一个逻辑的代码都收集在一起
单独写个hook
,然后再引入,这样就不到处分布,显得很乱了
Fragment
在
template
中不再需要一个根元素包裹
实际上内部会将多个标签包含在一个Fragment
虚拟元素中
好处: 减少标签层级, 减小内存占用
script
差异
来看看
script
和Vue2
的区别
-
可以再
script
使用ts
只需 设置lang
即可 -
defineComponent
方法创建一个组件 -
export default
直接导出一个组件
setup
setup
是Composition API
的入口
setup
执行顺序
它在beforeCreate
之前执行一次,beforeCreate
这个钩子 的任务就是初始化,在它之前执行,那么 this
就没有被初始化 this = undefined
这样就不能通过 this
来调用方法 和 获取属性
setup
返回值
setup
返回的是一个对象,这个对象的属性会与组件中 data
函数返回的对象进行合并,返回的方法和 methods
合并,合并之后直接可以在模板中使用,如果有重名的情况,会使用 setup
返回的属性和方法,methods
和 data
能够拿到 setup
中的方法应该进行了合并,反之 setup
不能拿到它们的属性和方法,因为这个时候 this
= undefined
Suspense
组件
setup
使用async
/await
我们需要 setup
返回数据那么它肯定就不能使用 async
修饰,这样返回 promise
是我们不想看见情况,如果我们硬要用 async
修饰,我们就得用的在它的父组件外层需要嵌套一个suspense
(不确定)内置组件,里面放置一些不确定的操作,比如我们就可以把异步组件放入进去
1.子组件
2.父组件
setup
参数
setup
(props
,context
)
setup
函数中的第一个参数是 props
。它接收父组件传递的值,是的就是父子组件信息传递的 props
第二个参数是 context
里面包含3个属性 { attrs, slots, emit }
,这三个属性大家看名字就应该知道是什么吧 分别对应 this.$attrs
,this.$slots
,this.$emit
-
attrs
: 除了props
中的其他属性 -
slots
: 父组件传入插槽内容的对象 -
emit
: 和用于父子组件通信
ref
定义/转为 响应式
在上面 setup
写的数据都不是响应式的,修改了数据,视图并不会更新
在 Vue3
中提供了两种方式定义响应式数据,先来介绍下 ref
导入 ref
方法
-
你可以先声明一个基本类型变量后再当做
ref
的形参穿进去 -
或者直接在
ref
中传入
来查看一下 number1
是什么吧
可以看见的是 number1
是一个 Ref
对象,我们设置的 10
这个值在这个对象的 value
属性上
也就是说我们修改的时候必须要修改的是 number1.value
通过给value
属性添加 getter
/setter
来实现对数据的劫持
但是在模板上使用的时候 不用写 number1.value
直接写 number1
即可
在模板编译的时候回自动加上 value
使用起来完全没有问题
刚才强调了说 ref
接收 基本类型的数据,那么它可以接收 复杂类型吗,object
类型等,当然可以
给 ref
传入复杂类型,其实它是调用 reactive
来实现的
reactive
下面会提到
ref
获取元素
同样的 ref
还可以用了获取元素
大家在 Vue2.X
中是怎么获取的呢,先在 标签上定义 :ref='XXX'
然后 this.$refs.XXX
来获取
在 Vue3
上获取元素就有些许不同了
1.首先在 模板元素上
ref='XXX'
这里不用v-bind
2.在
setup
中
得给 ref
指定类型 HTMLElement
如果在组件中需要使用到 haha
,就必须把 haha
return
出去合并 data
我们来看看打印的是什么
可以看见的是 haha
是个 Ref
对象,value
值就是我们想要获取到的元素
然后我们可以对 haha
这个 DOM
元素进行操作,比如这个
reactive
reactive
接收一个普通对象然后返回该普通对象的响应式代理对象
没错 它的底层就是使用 Proxy
进行代理
简单写个Vue3响应式例子来说下
Proxy
new Proxy(target, handler)
-
target
:要使用Proxy
包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理) -
handler
:一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理p
reactive
基础用法
导入,当然写的时候,vscode
会自动帮你引入
简单使用
来看看返回的 Proxy
对象吧
数据都在 target
中,
在模板使用直接 {{obj.name}}
即可
修改直接修改 obj[name]
=
‘xxx’
操作代理对象,obj中的数据也会随之变化,同时如果想要在操作数据的时候,界面也要跟着重新更新渲染,那么也是操作代理对象
响应式的数据是深层次的(递归深度响应式)
对于多层嵌套的数据也是响应式的
shallowReactive
它是一个简单的 reactive ,只把第一层的对象改为响应式,这里就不多说了
使用
ref
传入对象
实际上是 ref
使用 reactive
来进行操作的
toRefs
这个方法可以把 reactive
响应式对象,转化为 普通对象,普通对象的每个属性都是 Ref
对象,这样的话保证了 reactive
的每个属性还是响应式的,我们还可以把每个属性进行分解使用,这样在组件就不用 obj[属性],代码量减轻了,yyds
可以看见 name
和 age
已经变成了 Ref
对象
我们可以解构 出 name
和 age
单独使用
toRef
还有一个 toRef
方法,它的作用和 toRefs
差不多,但是它只能把响应式对象/普通对象的某一个属性变为 Ref
对象
可以用来为源响应式对象上的
property
性创建一个ref
。然后可以将ref
传递出去,从而保持对其源property
的响应式连接。
拷贝了一份新的数据值单独操作, 更新时相互不影响
当您要将 prop
的 ref
传递给复合函数时,toRef
很有用
可以从官方文档看出,用于在于组件之前的传递数据 从 props
拿出 'foo'
属性给复合函数,复合函数 useSomeFeature
,接收的参数 foo
为 Ref
类型,刚好可以使用toRef
来进行转化
判断响应式
几个判断是否哪种响应式创建的方法
1.isRef
: 检查一个值是否为一个 ref 对象
2.isReactive
: 检查一个对象是否是由 reactive
创建的响应式代理
3.isReadonly
: 检查一个对象是否是由 readonly
创建的只读代理
4.isProxy
: 检查一个对象是否是由 reactive
或者 readonly
方法创建的代理
customRef
上面提到了这么多的 Ref
都是 Vue 帮我们内置的,
我们可以通过 customRef
实现我们自己的 Ref
创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。它需要一个工厂函数,该函数接收
track
和trigger
函数作为参数,并应返回一个带有get
和set
的对象。
官方文档给了一个防抖的例子,我们也写个来看
shallowRef
和 shallowReactive
浅的响应式,一般用的不多,我们使用 ref
和 reactive
比较多
shallowReactive
对象结构多层嵌套,但是我们的需求只需要修改最外层的数据,就不用把里面的嵌套结构都转为响应式,这样使用浅的响应式提高性能,只有最外一层是响应式
比较容易理解,我这就里就不举例子了
shallowRef
我们之前说过 ref
也能传入一个对象,实际上还是调用 reactive
返回 Proxy
代理对象,如果内层还有对象,还是使用 reactive
进行处理
同样的 shallowRef
处理 对象类型,是交给 shallowReactive
去完成
这样子我们就明白了,为啥 只处理了 value
的响应式,不进行对象的 reactive
处理,适用于会被替换的数据
【注意】
:shallowRef
创建一个 ref
,将会追踪它的 value
更改操作,但是并不会对变更后的 value
做响应式代理转换
我们来打印下两个对象
可以看见的是 Ref
的 value
值是用 reactive
返回的 Proxy
对象,
shallowRef
的 value
是普通对象
readonly
和 shallowReadonly
readonly
深度只读
设置普通对象或者是响应式对象为只读,不能进行修改,看上面的名字就知道是深度的,深度是什么概念大家差不多都清楚,递归把内层的每一个属性都设置为只读,进行修改操作就会报错,提高了安全性
基本使用:
用什么就导入什么
果然在编译之前就报错了 Error
: 无法分配到 "name" ,因为它是只读属性
无论是内层还是外层都只读,是深度检测的
shallowReadonly
浅度只读
浅度的话只针对最外面一层不关心 内层
可以看下面的例子 只有外层的 name
报错,修改内层没有错误
toRaw
和 markRaw
这两个用的还是比较少
我这里就简单的过一下
toRaw
: 将一个响应式对象转为普通对象
简单使用:
两个打印出来,一个是响应式对象,通过 toRaw
后变成了普通对象
markRaw
: 标记一个对象,让它永远不会转为响应式对象,返回值是本身
比如:一些不变的数据死数据,还有一些第三方类实例,不用转为响应式对象,提高性能
简单使用:
这里使用 两个一样的对象,一个进行 markRaw
处理,一个不进行 markRaw
处理
然后同样使用 reactive
转为 响应式
可以看看打印的,被标记过的 obj
并没有转为 Proxy
响应式代理对象
computed
计算属性
在Vue3
中使用computed
和Vue2.X
有些不同,这里 computed
是一个方法
首先还是得导入
computed
方法
参数为一个回调 默认为 get
这里没有实现 set
方法,所以修改下面没有用
参数为一个对象 在这里写
get
set
模板和上面一样
watch
侦听器
和 Vue2.X 的 Watch 使用方法差不多
介绍
watch(data,handler,object)
-
data
:可以是返回值的getter
函数,也可以是ref
-
handler
:回调函数 -
object
:可选配置项{ immediate: true }
引入
data
为一个ref
回调函数的参数是 (新值,旧值)
可以看见页面第三栏没有显示,因为 name
值没有变化,所以就不用改变,watch
的第三个参数是 配置对象,我们在里面可以设置 立即执行 { immediate: true }
就会执行一次 当然这个时候 oldName
为 undefined
data
为一个getter
()=> haha
直接返回一个值,相当于 getter
简写,haha
可以不是响应式数据
data
为多个ref
模板还是之前那个
我们可以把多个 ref
放进一个数组里面
newNameAndAge
,oldNameAndAge
为一个数组保存着 新 和 旧的 [name,age]
data
为 reactive
这里是对象 会出现问题,立即执行后,
如果加上 立即执行 除了第一次 newInfo
为 {name: '小浪',age: 21}
oldInfo
为 undefined
,之后始终返回该对象的当前值
所以 newInfo
= oldInfo
对于这个问题,我们得加上配置对象 {deep: true}
进行深度检测
深度检测还可以判断多重嵌套
watchEffect
这个也是用来监听数据变化,默认就会执行一次所以这里就不需要配置,而且不用指定 data
,使用哪些响应式数据就监听哪些
provide / inject
提供 和 注入 是很简单理解的
实现跨层级组件(祖孙)间通信
在多层嵌套组件中使用,不需要将数据一层一层地向下传递
可以实现 跨层级组件 通信
在 父组件中
在 子孙 层级组件使用注入就能够获取到了
Teleport
传送组件
这个组件特别有趣,可以把组件进行传送
to
是目标的地址 body
, #XXX
, .XXX
这些都是 css
选择器
下面写个例子大家看下就明白了
模板
setup
setup() {
// target
let target = ref('.li_1')
return {
target,
}
},
利用 按钮 点击来控制 teleport
是否显示, teleport
一渲染,就会跑到 li
下面
Vue3
生命周期
Vue2.X
对应Vue3
组合API
可以看出
beforeCreate
和 created
在Vu3还是能正常使用,在Vue3我们可以用更好更快的 setup
代替
on
开头的 生命周期需要 通过 import
导入,在 setup
函数中使用
Vue3
的生命周期 比 Vue2.X
的生命周期快
举个例子: onBeforeMount
比 beforeMount
快 其他同理
还多个两个钩子:
-
onRenderTriggered
跟踪虚拟 DOM 重新渲染时调用 -
onRenderTracked
当虚拟 DOM 重新渲染被触发时调用
全局API
转移
Vue2.X
中 Vue
上面的全局API ,比如自定义指令 Vue.directive
,全局组件 Vue.component
在Vue3都进行改变,不再提供 Vue
,而是提供 app
具体改变可以看下面
结语
到了这里我们基本都了解了 Vue3
的一些特性
-
新的脚手架工具
vite
-
在
Vue3
仍然支持Vue2
中的大多数特性 -
Vue
组合APi
代替了Vue2
中的option API
,同一逻辑集中起来,复用性更强了 -
Vue3
使用TS
编写更好的支持TS -
Vue3
使用Proxy
代替了Vue2
中Object.defineProperty()
实现响应式原理 -
介绍了新的组件:
Fragment
Teleport
Suspense
这里还没有提到的 Vue3
重写了 虚拟DOM ,提高了性能
希望这篇笔记能够帮助到大家,如果我写的不清楚,具体的还得看 官方文档
参考资料:
Vue3官网文档: https://vue3js.cn/docs/zh
B站资料: https://www.bilibili.com/video/BV1Zy4y1K7SH?p=156
作者:小浪努力学前端
https://juejin.cn/post/7006518993385160711