您现在的位置是:首页 >技术杂谈 >Vue笔记第七章vue3【动力节点】网站首页技术杂谈
Vue笔记第七章vue3【动力节点】
7 Vue3
7.1 了解Vue3
- vue3官网地址
- vue3发布时间
- 2020年9月18日。
翻译:
今天,我们很自豪地宣布Vue.js 3.0“海贼王”正式发布。这个新的主要版本的框架提供了改进的性能斜体样式、更小的捆绑包大小、更好的TypeScript集成、用于处理大规模用例的新API,以及为框架未来的长期迭代奠定了坚实的基础。
3.0版本代表了两年多的开发工作,包括30多个RFC、2600多个提交、来自99个贡献者的628个拉取请求,以及核心回购之外的大量开发和文档工作。我们要向我们的团队成员表示最深切的感谢,感谢他们接受了这一挑战,感谢我们提出的撤回请求,斜体样式感谢我们的赞助商和支持者提供的财政支持,感谢广大社区参与我们的设计讨论并为预发布版本提供反馈。Vue是一个为社区创建并由社区支持的独立项目,如果没有您的持续支持,Vue 3.0是不可能实现的。
- 版本迭代历史
- vue3做了哪些改动
- 最核心的虚拟DOM算法进行了重写。
- 支持tree shaking:在前端的性能优化中,es6 推出了tree shaking机制,tree shaking就是当我们在项目中引入其他模块时,他会自动将我们用不到的代码,或者永远不会执行的代码摇掉
- 最核心的响应式由Object.defineProperty修改为Proxy实现。
- 更好的支持TS(Type Script:TypeScript是微软开发的一个开源的编程语言,通过在JavaScript的基础上添加静态类型定义构建而成。TypeScript通过TypeScript编译器或Babel转译为JavaScript代码,可运行在任何浏览器,任何操作系统。)
- …
- vue3比vue2好在哪
- 翻译:
- 与Vue 2相比,Vue 3在捆绑包大小(通过树抖动可轻41%)、初始渲染(快55%)、更新(快133%)和内存使用(少54%)方面都有了显著的性能改进。
- 翻译:
- Vue3的新特性
- 新的生命周期钩子
- 键盘事件不再支持keyCode。例如:v-on:keyup.enter支持,v-on:keyup.13不支持。
- 组合式API(Composition API)
- 新增了一些内置组件
- data必须是一个函数。
- …
- 新的生命周期钩子
7.2 Vue3工程的创建
7.2.1 vue-cli创建Vue3工程
- 创建Vue3版本的工程,要求vue-cli最低版本4.5.0
- 可以使用以下命令升级你的脚手架版本
- npm install -g @vue-cli
- 可以使用以下命令升级你的脚手架版本
- 创建Vue3工程
- vue create vue3_pro
- 启动工程
- 切换到工程根目录。
- npm run serve
7.2.2 vue-cli创建的vue3项目说明
- 目录结构以及文件和vue2相同。
- main.js文件说明
- 查看App.vue组件
vue3中template标签下可以有多个根标签了。
7.2.3 create-vue创建Vue3工程
- create-vue是什么?
- 和vue-cli一样,也是一个脚手架。
- vue-cli创建的是webpack+vue项目的脚手架工具。
- create-vue创建的是vite+vue项目的脚手架工具。
- webpack和vite都是前端的构建工具。
- vite官网
- vite是什么?(vite被翻译为:快)
- vite是一个构建工具,作者尤雨溪。
- 前端构建工具有哪些?
- vite和传统构建工具的区别?
- 使用vite后,至少两方面是提升了:
- 服务器启动速度快。
- 更新速度快了。
- 使用create vue创建Vue3工程
- 官方指导:https://cn.vuejs.org/guide/quick-start.html
- 安装 create-vue脚手架并创建vue3项目:npm init vue@latest
执行时,如果检测到没有安装create-vue脚手架时会安装脚手架。如果检测到已经安装过脚手架,则直接创建项目。
一路选择No:
- cd vue3_pro
- npm install
- npm run dev
- 访问5173端口
7.2.4 create-vue创建的vue3工程说明
- 目录结构
- 和vue-cli脚手架创建的区别
- index.html文件不再放到public目录下了。
- vite官方的解释是:让index.html成为入口。(vue-cli脚手架生成的项目入口是:main.js)
- index.html文件不再放到public目录下了。
- vue-cli的配置文件vue.config.js。create-vue脚手架的配置文件:vite.config.js
- vite.config.js 能配置什么?可以参考vite官网:https://cn.vitejs.dev/config/ 例如配置代理服务器和以前就不太一样了。
7.3 Proxy实现原理
Vue2的响应式核心:Object.defineProperty
Vue3的响应式核心:Proxy
7.3.1 Object.defineProperty
get做数据代理。set做数据劫持。在set方法中修改数据,并且渲染页面,完成响应式。
Object.defineProperty(data, ‘name’, {
get(){
// 数据代理
},
set(val){
// 数据劫持
}
})
存在的问题:
- 通过数组下标修改数据,这个操作是没有响应式的。
- 后期给对象新增属性、删除属性,这些操作都是没有响应式的。
导致以上问题最根本原因是:Object.defineProperty只能捕获到读和修改。
Vue2中怎么解决以上问题?
- 对于数组来说调用数组的相关API。例如:push、shift、unshift…
- 新增属性、删除属性等操作通过:Vue.set或者this.$set
7.3.2 Proxy
Proxy是ES6新增特性。window.Proxy
Proxy是一个构造函数,参数传递一个目标对象,可以为目标对象生成代理对象。
通过访问代理对象上的属性来间接访问目标对象上的属性。
访问代理对象上的属性时,读属性、修改属性、删除属性、新增属性。Proxy都可以捕获到。
Vue3框架底层实际上使用了ES6的Reflect对象来完成对象属性的访问:
7.4 setup
- setup是一个函数,vue3中新增的配置项。
- 组件中所用到的data、methods、computed、watch、生命周期钩子…等,都要配置到setup中。
- setup函数的返回值:
- 返回一个对象,该对象的属性、方法等均可以在模板语法中使用,例如插值语法。
- 返回一个渲染函数,从而执行渲染函数,渲染页面。
- import {h} from ‘vue’ (引入渲染函数)
- return ()=>{h(‘h2’, ‘欢迎大家学习Vue3’)}
- vue3中可以编写vue2语法,向下兼容的。但是不建议。更不建议混用。
- setup中的this是undefined。所以setup中this是不可用的。
7.5 ref函数(实现响应式)
7.5.1 简单数据的响应式
- ref是一个函数。完成响应式的。
- ref使用时需要import
- import {ref} from ‘vue’
- 凡是要实现响应式的data,需要使用ref函数进行包裹
- let name = ref(‘李四’)
- 输出name,你会发现,它是RefImpl对象(引用实现的实例对象,简称引用对象),在这个引用对象当中有一个value属性,value属性的实现原理是:Object.defineProperty,通过它实现了响应式处理。
- 修改数据的话必须这样做:name.value = ‘王五’
7.5.2 对象数据的响应式
重点:如果ref函数中是一个对象,例如:ref({}),底层会为这个对象{}生成一个Proxy代理对象。通过这个代理对象完成了响应式。
如果代码是这样写,如下,实际上没有用到Proxy,还是使用了Object.defineProperty完成的响应式:
如果代码是这样写,如下,就是使用了Proxy完成的响应式:
7.6 Vue3中专门为对象做响应式的核心函数:reactive
以上代码中的Proxy是怎么创建的?底层是通过调用reactive函数来完成的。
当然这个函数我们也可以自己使用。
注意:这个函数不能为简单类型服务,只能为对象类型服务。
注意:reactive为响应式做了递归处理。对象中的对象中的对象的属性,也是响应式的。
重点1:
并且数组如果使用reactive函数包裹的话,数组中的数据,在通过下标去修改的时候,也是支持响应式的。(这个在Vue2中是不支持的。)
重点2:
在开发中一般很少使用ref,一般会使用reactive。即使是简单类型的数据,也会将其存放到一个对象中,使用reactive函数进行包括。
7.7 Vue3中的props
给组件User传数据
User组件使用props接收数据
在setup函数中如何使用props?
setup的第一个参数就是props。可以直接拿来用。
7.8 Vue3的生命周期
vue2的生命周期图:
vue3的生命周期图:
- vue2中
- beforeDestroy
- destroyed
- vue3中
- beforeUnmount
- unmounted
- vue3中仍然可以使用配置项方式提供生命周期钩子函数。但也可以使用组合式API方式。如果采用组合式API方式,API名称规律如下:
- beforeCreate => setup
- created => setup
- beforeMount => onBeforeMount
- mounted => onMounted
- beforeUpdate => onBeforeUpdate
- updated => onUpdated
- beforeUnmount => onBeforeUnmount
- unmounted => onUnmounted
- 当然如果需要使用beforeCreate和created钩子,可以采用vue2的语法:配置项形式。vue2和vue3语法可以共存,但不建议。
7.9 Vue3中的自定义事件
绑定事件
触发事件
7.10 Vue3的全局事件总线
- 安装mitt
- npm i mitt
- 封装event-bus.js文件
- 绑定事件
- 触发事件
- 移除所有事件和指定事件
7.11 vue3的计算属性
import {computed} from ‘vue’ //computed是一个组合式的API。
setup(){
// 简写
let reversedName = computed(()=>{
})
// 完整写法
let reversedName = computed({
get(){},
set(value){}
})
}
计算属性最重要的特征是:只要计算属性关联的数据发生变化,计算属性的回调函数就会执行。所以计算属性关联的数据必须是具有响应式的。
7.12 自定义hook函数
将组合式API拿出来,封装成一个函数,在需要复用的位置,使用这个hook函数。
一般创建一个hooks目录,在hooks目录当中放hook函数。
代码复用。
在需要使用的位置导入:
7.13 vue3的监视属性
import {watch} from ‘vue’ //watch就是组合式API。
- 监视ref定义的一个响应式数据
- watch(数据, (newValue, oldValue)=>{})
- 监视ref定义的多个响应式数据
- watch(数据1, (newValue, oldValue)=>{})
- watch(数据2, (newValue, oldValue)=>{})
或者
- watch([数据1,数据2], (newValue, oldValue)=>{})
- immediate在哪里写?
- 在watch的第三个参数位置上使用一个对象:{immediate : true, deep:true}
- 监视reactive定义的响应式数据。注意:oldValue拿不到
- watch(数据, (newValue, oldValue)=>{})
- 如果监视的reactive定义的响应式数据。强制开启了深度监视,配置deep无效。默认就是监视对象的全部属性。
- 如果要监视对象中的某个属性怎么办?被监视的数据必须是一个函数,将要监视的数据返回
- watch(()=>user.age, (newValue,oldValue)=>{})
- 如果要监视对象中的某些属性怎么办?
- watch([()=>user.age, ()=>user.name], (newValue,oldValue)=>{})
- 如果要监视reactive定义的响应式数据中的某个属性,这个属性是一个对象形式,那么开启deep:true是可以的。
- watch(()=>user.address, (newVal, oldVal)=>{})
- 关于ref包裹对象时的value
- watch(name.value, (newVal, oldVal){}) //监视无效
- watch(user.value, (newVal, oldVal)=>{})//监视有效
- watch(user,(newVal, oldVal)=>{}, {deep:true}) // 深度监视生效
7.14 watchEffect函数
- watchEffect函数里面直接写一个回调
- 回调中用到哪个属性,当这个属性发生变化的时候,这个回调就会重新执行。
- watchEffect(()=>{const a = data.counter1; const b = data.counter2 逻辑代码…}) 当counter1和counter2被修改后,这个回调就会执行。
- computed和watchEffect的区别?
- computed注重返回结果。
- watchEffect注重逻辑处理。
- 示例代码
7.15 shallowReactive和shallowRef
浅层次的响应式。
shallowReactive:对象的第一层支持响应式,第二层就不再支持了。
shallowRef:只给基本数据类型添加响应式。如果是对象,则不会支持响应式。
以下是演示shallowRef
以下是演示shallowReactive
7.16 组合式API和选项式API对比
组合式API:Composition API
选项式API:Options API
选项式API:特点是 分散。
组合式API:特点是 集中 (一个hook是一个独立的功能,一个hook中有自己的data、methods、computed、watch)
7.17 深只读与浅只读
组合式API:readonly与shallowReadonly
应用场景:其它组件传递过来的数据,如果不希望你修改,你最好加上只读,以防以后不小心改了人家的数据。
深只读:
浅只读:
7.18 响应式数据的判断
isRef:检查某个值是否为 ref。
isReactive:检查一个对象是否是由 reactive() 或 shallowReactive() 创建的代理。
isProxy:检查一个对象是否是由 reactive()、readonly()、shallowReactive() 或 shallowReadonly() 创建的代理。
isReadonly:检查传入的值是否为只读对象。
7.19 toRef和toRefs
通过以上写法,可以看到模板语法中都有“data.”,这个是可以改善的。
大家可以看一下,下面的这个改善是否可以?
我们发现这样修改是不行的。丢失了响应式。什么原因?主要原因是因为以上的这种写法等同于:
显然这种写法和响应式对象data无关了。
再修改为以下这样行不行?
我们发现功能实现了。但是存在的问题是:data不会变。例如:
怎么解决这个问题:toRef,它可以让数据具有响应式,并且修改toRef生成的对象时,还能关联更新data:
测试结果:
还有一个更简单的:toRefs
运行结果:
7.20 转换为原始&标记为原始
toRaw与markRaw
toRaw:将响应式对象转换为普通对象。只适用于reactive生成的响应式对象。
markRaw:标记某个对象,让这个对象永远都不具备响应式。比如在集成一些第三方库的时候,比如有一个巨大的只读列表,不让其具备响应式是一种性能优化。
toRaw:
markRaw:
7.21 Fragment组件
fragment翻译为:碎片。片段。
在Vue2中每个组件必须有一个根标签。这样性能方面稍微有点问题,如果每一个组件必须有根标签,组件嵌套组件的时候,有很多无用的根标签。
在Vue3中每个组件不需要有根标签。实际上内部实现的时候,最终将所有组件嵌套好之后,最外层会添加一个Fragment,用这个fragment当做根标签。这是一种性能优化策略。
7.22 Teleport组件
teleport翻译为:远距离传送。用于设置组件的显示位置。