前言
作为一名前端开发者,不可能不知道vue,而vue3.0的到来告诉我们,学习的脚步不能停,只要学不死,就往死里学 下面是我的关于Vue3.0的学习日记。
VUE3.0的目标
更小
- 打包大小减少41%
- 内存减少54%
更快
- 初次渲染快55%, 更新渲染快133%
更友好
- 可以更好的支持TypeScript
一、VUE3.0的项目搭建
通过脚手架搭建
- 查看@vue/cli版本,确保@vue/cli版本在4.5.0以上: vue --version
- 安装或者升级你的@vue/cli: npm install -g @vue/cli
- 创建vue3.0 项目: vue create vue_demo
- 运行项目: npm run serve
- 打包项目:npm run build
参考官方文档:
cli.vuejs.org/zh/guide/cr…
通过vite搭建(推荐)
- 通过命令行安装: npm init vite -- --template vue
- 安装依赖:npm install
- 运行项目:npm run serve
参看官方文档(Vite): vitejs.cn/
项目搭好了,接下来就开始了解Vue3.0
二、 setup():拉开VUE3的序幕
setup是什么
官方定义为组合式API,主要是为了该变以前使用(data、computed、methods、watch)在编写时造成视图过长,让组件变得太大,使得阅读困难的情况。
怎么用
在之前的vue3版本中,setup()是以函数的形式包裹在export default中,和data(),method类似如下图:
但是在新的vue版本中,setup已经成为了一个一个语法糖放入了script标签中,使用更加方便,代码更加简洁,所以推荐在vue3.0的开发使用一下这种方法:
我们可以在这个标签内完成我们基本上所有的业务,例如定义变量,事件,或是使用数据监听,组件通信等等后续中会讲到如何使用。
注意点
- 从生命周期的角度来说,setup()函数执行是在beforeCreate前。
- setup讲究无this,所以在这里面无法使用this,因为在setup内部this是一个undefined
三、生命周期
在学vue2时最开始看的也是生命周期,所以在vue3时,也先对比一下两者生命周期的,总体上来说大致一样,只是vue3中把beforeDestroy和destroy变成了beforeUnmounted,unmounted,如下图所示:
在setup中的使用如下图:
四、数据绑定(响应式)
API
ref(监听基本数据类型:Number,Boolean,String,Null,Undefined)
注:ref也可以接受复杂数据类型,但是他在内部会“求助”reactive帮助,所以不建议使用ref来包装复杂数据类型
(经过几个项目编写习惯性用ref一把梭,感觉也没啥问题,有不同意见的欢迎评论区留言)
ref原理
基本数据类型依旧是采用如vue2的方法来实现的,也就是说响应式依然是靠Object.defineProperty()的get与set完成的如图。
reactive(监听复杂数据类型:Array,Object)
reactive原理
reactive是定义一个对象类型的响应式数据,所以基本数据不要使用它,它会返回一个代理对象(Proxy的实例对象,内部通过Proxy实现),他的好处就是提高了监听的效率,并且对对象和数组的监听更加友好,相当于也算修复了vue2中对象和数组无法触发双向绑定的问题。
vue3 和 vue2 数据绑定实现区别
vue2
通过数据劫持的方式,使用Object.defindeProperty()对属性得到读取、修改进行拦截。对数组的话,通过重写更新数组的一系列方法来实现拦截。
Object.defineProperty(data, 'count', {
get(){},
set(){}
}
存在问题:
- 新增属性、删除属性,界面不会更新
- 直接通过下标修改数组,界面不会自动更新
vue3
- 通过Proxy(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。
- 通过Reflect(反射): 对源对象的属性进行操作。
new Proxy(data, {
// 拦截读取属性值
get (target, prop) {
return Reflect.get(target, prop)
},
// 拦截设置属性值或添加新属性
set (target, prop, value) {
return Reflect.set(target, prop, value)
},
// 拦截删除属性
deleteProperty (target, prop) {
return Reflect.deleteProperty(target, prop)
}
})
五、数据监听:watch 和 watchEffect(新)
watch的使用
总体上来说vue3的watch和vue2的差别不大。在vue3.0中watch使用函数,支持传入三个参数即watch(target,callback,options),
第一个是监听对象,
第二个为回调函数,
第三个是配置({immediate:true,deep:true,flush:pre | post})
补充
flush 使用的比较少的一个配置,默认是pre,这个参数相当于可以控制immediate的为true时watch回调函数执行的时间,当设置为post时会将回调函数放入一个微任务中,这样可以使得这个回调函数在DOM渲染后执行,也就是在onMounted生命周期后执行。
先奉上官方文档:v3.cn.vuejs.org/api/compute…
以下是使用案例:
1、监听ref定义的基本类型响应式数据
2、监听reactive定义得到复杂数据类型
补充
watch在监听reactive对象时会自动开启深度监听
3、同时监听多个数据
补充
const unwatch = watch(msg,(newVal,oldVal) =>{})
//可以通过unwatch停止监听
unwatch()
再次补充
其实在watch(obj, (newValue,oldValue,onInvalidate)=>{})中watch第二个函数中是存在第三个参数onInvalidate这个参数用的不多,但关键时刻还挺有用的可以了解一下,详细参考《Vue.js设计与实现》78页
onInvalidate出现是为了解决watch中出现的竞态问题,即异步请求时数据被覆盖的情况,具体使用方式如下:
watch(obj,async(newValue,oldValue,onInvalidate)=>{
let expired = false
//调用onInvalidate()函数注册一个过期回调
onInvalidate(()=>{
expired = true
})
const res = await fetch('/path/to/request')
if(!expired){
finalData = res
}
})
如上面的代码所示,在发送请求之前,我们定义了expired标志变量,用来标识当前副作用函数的执行是否过期;接着调用 onInvalidate 函数注册了一个过期回调,当该副作用函数的执行过期时将expired标志变量设置为true;最后只有当没有过期时才采用请求结果,这样就可以有效地避免竞态问题了。
watchEffect
vue3.2版本有了新的用法,具体参考官方文档:
v3.cn.vuejs.org/guide/react… 官方解释:立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。
用通俗的话说就是,我不指定我要监视谁,在我包裹里面的响应式变化了那么我就触发回调函数。如下:
六、另一个数据监听computed
vue3中的computed和vue2基本一致,使用方式如下:
补充:
computed 最大的好处就是数据缓存,它会保存每一次的执行结果。如上图,在每次使用complexMsg.value时computed 会优先使用它内部缓存的结果,如果他内部使用的响应式数据存在变化时才会重新去计算结果,这里用到的就是响应式的依赖触发,具体源码中涉及到的知识点就是副作用函数的调度控制和缓存控制,详细可参考数据《vue.js涉及与实现》64页。
总之:computed缓存的使用能够达到一些性能优化,特别是在计算数据量大的情况下。