创建Vue3

注意开发者工具要更新才能点亮
使用vite:

一些变化
main.js的变化
不再使用引入并创建整个vm的方式,而是引入一个vue的方法
createApp创建一个应用实例,然后渲染这个实例

对应mount方法的还有一个相反的unmount方法
不兼容vue2的写法,也无法直接引入vue了
template可以没有根标签

开发者工具应安装vue3

vue2与vue3的响应式区别

vue2增删属性必须使用$set和$delete这两个api才能被响应
vue3通过reactive生成的对象直接增删属性是可以被响应的

删除使用delete关键字释放资源
常用Composition(组合式)API
setup

setup是值为函数的新配置项,半取代了data与methods
(data内也可配置函数,但不具备响应式,必须配置在methods)
属性名冲突时,setup的优先级高于data/methods,并且仅支持data/methods向setup单向访问,不应混用
由于setup是函数,而配置data/methods时是使用对象,因此setup使用的不是key-val的形式,而是直接在函数里面写数据
由于数据与函数都在同一作用域,引用数据无需使用this.name
同步组件内,setup不允许被async(异步函数)修饰,因为返回值会被自动包装为promise。访问时得用.then,因而不是一个单独的对象

setup返回对象时,则类似data,属性方法都可以直接使用,但方法无法引起数据的响应式变化,除非数据使用ref函数

setup返回渲染函数时,会将整个页面替换掉,以渲染函数为主
要构造渲染函数,还需要引入h,设置返回值为h函数的返回值![]()

ref函数

ref函数在使用时需要引入
原本在setup内的数据无法实现响应式,但调用ref函数可实现
在setup内通过ref函数配置数据:

本质上,调用ref后返回的数据变成了RefImpl(引用实现)对象

setup里的函数要实现响应式操作,得修改对象里的value属性值,从而触发getter和setter

vue在解析模板时会自动识别并读取value值,无需手动读取

ref处理对象类型
ref将对象类型的数据处理成Proxy类型,作为RefLmpl的value
读取xx.valuie时,会返回该对象的Proxy形式,而不再包含value
因此读取对象内属性值的操作应为xx.value.xx
即便没有第二层,多层的数据也能被监测到并进行响应式变化,因为RefImpl只有处理基本数据类型才用getter/setter
reactive函数

使用reactive函数仍然需要引入

reactive的使用方式与ref相同,都是直接传入需要响应的值

reactive将收到的值转为Proxy对象,使用时无需找value属性![]()
reactive也可以用于处理数组的响应式,并且可以深度响应
**为避免因使用ref而重复使用value,应该尽量将数据设置成对象,**并使用reactive生成Proxy对象数据,作为一个setup返回值内的一个属性

Vue3的响应式原理

vue2的响应式只能捕获增删的时候

vue3实现响应式使用了window自带的Proxy方法
对代理对象的任何修改都会被proxy捕获到,完成对源数据的修改,从而再反馈给代理对象
使用Proxy的getter和setter,外加一个deleteProperty
getter的两个参数,第一个target是源对象,第二个propName是读取的属性名,读取时要避免引起递归
setter的三个参数,第一个target是源对象,第二个propName是修改的属性名,第三个是原属性值
deleteProperty的两个参数,第一个target是源对象,第二个propName是删除的属性名

vue底层不再使用Object.defineProperty,改为使用Reflect.defineProperty,因为Object的重复定义会引发错误并终端线程,而reflect仅返回是否正常运行结果,不影响后续代码执行

reactive对比ref

在使用时,可以在setup内通过reactive定义一个data对象,然后将这个对象作为返回值,达成类似vue2的数据书写方式
setup的两个注意点

computed函数
setup内不再作为配置项去配置,而是一个函数,用法基本一致

仍需先引入
使用的时候传入参数有两个形式
传入回调函数的时候是简写形式,没有多余配置项,回调函数直接返回计算好的数值。并且此时的计算属性是只读的
可以直接在reactive代理对象上配置一个计算属性

传入对象的时候,包含getter和setter,可以读写

watch函数

vue2配置方式仍然可用,depp也是可选项
vue3的watch是函数,第一个参数是要监视的数据,第二个参数是回调函数或者对象,第三个参数是配置项
情况一:
包含两个参数newval和oldval,
用于监视ref定义的一个响应式数据

情况二:
可以监视ref所定义的多个响应式数据
watch的第一个参数变为数组
回调函数的两个参数变为多个newval和oldval组合的数组

情况三:
监视reactive所定义的对象数据时,
无法正确获得oldVal,并且强制开启了深度监视

如图的deep
情况四:
监视reactive所定义的对象数据的某个属性
此时watch函数第一个参数变为回调函数,返回值为数据

情况五:
监视reactive所定义的对象数据的某些属性
watch函数的参数变为回调函数数组
回调函数的参数变为newval和oldval的数组

情况六:
监视reactive所定义的对象数据的某些对象属性
虽然监视reactive对象的属性在参数形式时强制开启深度监视,但是在监视reactive对象的对象属性时需要手动配置deep才能深度监视

watch时value的问题
监视ref时无需.value,因为.value之后会把数据取出来,变成监视一个固定值,因此直接监视整个ref实例对象即可,newval与oldval都是value值
如果监视的数据是对象,并且通过ref生成,则需要.value,此时传的是reactive定义的对象,并且会强制对其深度监视。或者不.value,但是自己手动配置deep
watchEffect函数

watchEffect函数只有一个参数,参数为回调函数
这个回调函数内用到了哪个数据,则对哪个数据进行监视

Vue3生命周期
Vue3去掉了判断是否有el的选项,而是在一开始就必须要有el
另外,beforeUnmount跟unmounted更名为beforeDestroy跟destryed,将销毁换成了卸载组件
vue3使用组合式api,使得生命周期钩子可以在setup里使用
使用组合式api的钩子时也需要引入

如果仍以vue2的形式配置钩子,则setup的执行时机在beforeCreate之前
如果在vue3中使用组合式api,则setup就相当于beforeCreate与created两个钩子
这些组合式api的钩子均为函数形式,参数为回调函数
如果vue3组合式api与vue2的钩子同时使用,则vue3的优先

自定义hook函数

实现捕获鼠标点击坐标

使用原来的方法,需要在组件内window上挂载监听并及时卸载
而且要把逻辑函数写在外部,挂载和卸载的时候都需要函数名
使用hook,将该部分代码移植到公共区
在src目录下创建hooks文件夹,将该部分代码封装到该文件夹下usePoints.js文件内
**将该实现的全部逻辑封装成函数,且返回数据,**将该函数暴露出去
注意所使用的vue方法都需要重新引入
vue在setup里写的的组合式api都与hook封装的函数类似

使用该函数时需要引入并调用

vue2中的mixin





toRef与toRefs

使用时需要引入

对name1的赋值不会引发任何响应式变化,实际上就是普通赋值
而name2使用toRef方法,将name2绑定到了person的name属性,对name2的读写会引发person的name属性的响应式变化
如果使用ref而不是toRef,则name2与person不绑定,是新对象
name2通过toRef函数成为了一个RefImpl对象,并引用了原数据
通过该方法,可以将打包的数据逐个解包,且保留响应式变化
**作为setup的返回值,**在返回时拆解person

使用toRefs批量处理


toRefs的批量处理会把所以对象的属性都转化成RefImpl,对于包含子对象的对象,也会正常将其变成Proxy对象
使用…直接简写拆分所有属性

其他Compisition API
注意:所有组合式api使用时都要引入

shallowReactive与shallowRef:数据的浅层响应式

shallowReactive与reactive的区别在于是否深层响应式
shallowRef与ref的区别在于,使用对象时是否有响应式,因为不求助reactive,value值就是普通对象类型
readonly与shallowReadonly:响应式数据转为(深/浅)只读

readonly默认是深只读,shallowReadonly只让第一层属性只读
ref数据没有深层,一般用浅只读
reactive数据有深层,一般用深只读
toRaw与markRaw:把响应式对象转为原始普通对象

toRaw只能将reactive生成的响应式对象退回
markRaw:阻止对象变成响应式对象
应用:
reactive定义的对象是深层响应式的,并且在该对象上追加属性的时候,会自动转为响应式属性。如果追加的数据不希望其被转为响应式,则应使用markRaw(如第三方库、不可变数据)

customRef:自定义ref
如:实现延迟响应式(防抖)
customRef是一个函数,参数为回调函数,该回调必须返回对象
回调的参数有两个,track与trigger
get里使用track()追踪响应式数据,
set里使用tigger()触发响应式数据的改变
返回的对象必须包含两个函数:get()和set()
get没有参数,由于作用域问题可以直接取得响应式的value,同时需要使用track()实现对响应式数据的追踪
set的参数为修改时,想要修改的新值。在set里可以把响应式的value直接进行修改,不会引发递归,但是此时getter未响应**,需要使用trigger触发一次重新解析**

如果需要延迟响应,只需要修改触发响应的逻辑

如果只设置定时器,而不在设置定时器之前清除旧的定时器,则会使得新旧定时器堆积在一起触发
provide与inject:祖孙(跨级)通信


provide是一个函数,参数为属性和值(祖先组件)
inject是一个函数,参数为需要使用的属性(后代组件)
只要祖先组件进行provide,任何后代组件都可以进行inject
一般只有祖孙及其后代进行注入,父子不使用注入但其实能使用

响应式数据的判断

返回值均为布尔值
注意:readonly只改变是否只读,原数据是什么类型还是什么类型
CompositionAPI的优势
optionsAPI的缺陷:

compositionAPI的优势:使用hook函数将代码聚合,降低耦合度

新的组件
Fragment:代替组件根标签

Teleport:组件html移动

teleport标签的作用是,将指定的html结构传送到指定的html标签内

如在设置弹窗时,弹窗显示时可能会将父组件撑开,而如果要将弹窗进行定位,可能需要层层去找父组件才能进行定位


使用teleport标签可将弹窗移动到指定标签内,此处放在body内
Suspense(目前处在试验阶段)
异步组件
如果都是用同步组件,则嵌套的组件的加载速度是以速度最慢的为准,容易造成一起堵塞
正常的引入组件,是同步组件
引入异步组件,需要先从vue引入定义异步的函数,再引入组件
该函数的参数是一个回调,回调的返回值是import函数,参数是引入的组件的位置
Suspense实现未加载时的显示
将组件套在Suspense标签内,内部包含多个template标签
在template标签上添加v-slot属性(注意使用的是冒号),
默认的slot包含加载的原标签,当该标签未被加载出来时,使用slot为fallback的标签代替原本的标签

异步组件内setup可返回promise

如果引入异步组件,可以通过返回一个promise的方式,主动实现组件的延迟加载(本质上是延迟了setup的返回,延长钩子周期)
Vue3中其他改变
全局API的转移



其他改变




native用于声明原生事件,改为在子组件声明自定义事件


如果这篇文章对你有帮助,欢迎分享给更多人!
部分信息可能已经过时















