目录
(一)Vue3生命周期
1.vue3中被改名的钩子如下
beforeDestroy ==> beforeUnmount
destroyed ==> unmounted
2.vue3提供了组合式api的钩子,和vue2的对应如下
beforeCreate ==> setup()
created ==> setup()
beforeMount ==> onBeforeMount
mounted ==> onMounted
beforeUpdate ==> onBeforeUpdate
updated ==> onUpdated
beforeUnmount ==> onBeforeUnmount
unmounted ==> onUnmounted
3.组合式api内的生命周期钩子执行时间比配置项生命周期钩子要早
(二)自定义hook
hook,本质是一个函数。自定义hook,就是将setup中使用的组合式函数进行封装,实现代码复用;与vue2的mixin类似 ;
自定义Hooks是为了处理组件逻辑的一种模式。它可以让我们在不使用组件之间复制粘贴代码的情况下重用状态逻辑。自定义hooks是简单的JavaScript函数,但是在使用是,我们要遵循两个重要(不成文)的命名约定:
- 它们以use开头。
- 它们可以调用其他的hook。
例如:实现获取鼠标坐标的函数,封装到文件中,组件需要就可以引入调用
在hooks/usePoints.js中:
// 自定义钩子 实现获取鼠标打点坐标
import { reactive, onMounted, onBeforeMount } from 'vue'
export default function () {
const position = reactive({
x: 0,
y: 0
})
// 实现鼠标打点
function getPosition(event) {
position.x = event.pageX
position.y = event.pageY
console.log(event.pageX, event.pageY);
}
onMounted(() => {
window.addEventListener('click', getPosition)
})
onBeforeMount(() => {
window.removeEventListener('click', getPosition)
})
return position
}
组件中调用:
import usePoints from './hooks/usePoints'
export default {
setup() {
let point = usePoints()
return { point }
}
}
(三)toRef和toRefs
1.toRef
作用:创建一个 ref 对象,其value值指向另一个对象中的某个属性
语法:const name = toRef(person ,'name')
应用:要将响应式对象中的某个属性单独提供给外部使用时
setup() {
let person = reactive({
name: 'csq',
age: 18,
job: {
salary: 2000
}
})
return {
// toRef 创建一个新的ref对象,使得它的value值是person的某个属性的值,且能够实现响应式
// name:ref(person.name) 虽然能够实现响应式,但动态改变的是return的这个name,而不是person.name
name: toRef(person, 'name'),
age: toRef(person, 'age'),
salary: toRef(person.job, 'salary'),
}
}
错误思路:
- name:person.name 只是将person.name的静态数据传递给了name,不具备响应式;
- name:ref(person.name) 虽然能够实现响应式,但动态改变的是return的这个name,而不是person.name;
2.toRefs
toRefs 与 toRef 功能一致,但可以批量创建多个 ref 对象,
语法:toRefs(person)
// toRefs 可以批量创建多个对象 如果是嵌套对象,只能打开第一层
return{
...toRefs(person),
}
(四)其他组合式api
1.shallowRef和shallowReactive
shallowRef: 只处理基本数据类型的响应式不进行对象的响应式处理
shallowReactive:只处理对象最外层属性的响应式(浅响应式)
什么时候使用?
- 如果有一个对象数据,后续功能不会修改该对象中的属性,而是生新的对象来替换 => shallowRef
- 如果有一个对象数据,结构比较深,但变化时只是外层属性变化 => shallowReactive
2.readonly和shallowReadonly
readonly:让一个响应式数据变为只读的(深只读)
shallowReadonly:让一个响应式数据变为只读的 (浅只读)
应用场景:不希望数据被修改时
import { ref, reactive, readonly, shallowReadonly } from 'vue'
// 深只读 所有属性包括嵌套对象都不能修改 会发出警告
let p1 = readonly(person)
// 浅只读 嵌套对象的第一层属性不能被修改
let p2 = shallowReadonly(person)
3.toRaw和markRaw
(1)toRaw
作用:将一个由 reactive 生成的响应式对象转为普通对象
使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面更新
(2)markRaw:
作用:标记一个对象,使其永远不会再成为响应式对象
应用场景:
- 有些值不应被设置为响应式的,例如复杂的第三方类库等
- 当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能
4.customRef
作用:创建一个自定义的 ref,显式声明对其依赖追踪和更新触发的控制方式
实例:创建一个有防抖功能的自定义ref
setup() {
// 一个防抖功能的自定义ref函数 delay:防抖延迟时间
function useDebounceRef(value, delay = 200) {
let timeout
return customRef((track, trigger) => {
return {
get() {
track() // 通知vue追踪数据的改变
return value
},
set(newValue) {
clearTimeout(timeout) //清除定时器 保证最后一次修改时延时set
timeout = setTimeout(() => {
value = newValue
trigger() // 通知vue重新解析模板,更新页面数据
}, delay)
}
}
})
}
// 定义一个自定义ref的数据
let str = useDebounceRef('hello', 500)
return {
str
}
}
track:通知vue追踪数据的改变
trigger:通知vue重新解析模板,更新页面数据
5.provide和inject
作用:实现爷孙组件之间的通信
由于vue3框架原因导致vue2使用的全局事件总线被取消,在vue3使用provide和inject函数可以实现父组件和它的后代组件之间可以进行通信(父子通信还是建议用props)
爷爷组件发起数据
import {provide} from 'vue'
// 发出数据
provide('thing', thing)
后代组件组件接收数据
import { inject } from 'vue';
// 接收数据
let thing = inject('thing')
6.响应式数据的判断
isRef():检查某个值是否为 ref。
isReactive():检查一个对象是否是由reactive()或shalloReactive()创建的代理。
isReadonly():检查传入的值是否为只读对象。只读对象的属性可以更改,但他们不能通过传入的对象直接赋值
isProxy():检查一个对象是否是由 reactive()、readonly()、shallowReactive() 或 shallowReadonly() 创建的代理。
(五)组合式api的优势
1.Options API的缺点
使用传统Options API(配置式API)中,新增或者修改一个需求,就需要分别在data,methods,computed里修改
2.Composition API的优势
- 代码集中化,每一个功能的data、methods、computed等都写在一起,方便管理
- 代码复用更方便,将实现同一功能的代码段封装在自定义hook内,可以真正实现组合式api
(六)vue3的新组件
1.Fragment组件
在Vue3中,组件可以没有根标签,内部会将多个标签包含在一个Fragment虚拟元素中
好处:减少标签层级,减小内存占用
2.Teleport组件
作用:<Teleport> 是一个内置组件,它可以将一个组件内部的一部分模板“传送”到该组件的 DOM 结构外层的位置去
使用场景:一个组件模板的一部分在逻辑上从属于该组件,但从整个应用视图的角度来看,它在 DOM 中应该被渲染在整个 Vue 应用外部的其他地方。如,全屏模态框。
举例:孙组件点击弹窗弹窗弹出,再点击弹窗关闭,但弹窗位置出现在整个页面正中再加个遮罩层会更好看
<button @click="isShow = true">点我打开弹窗</button>
<!-- 将这段弹窗样式传送到body标签上 -->
<teleport to='body'>
<!-- 遮罩层 -->
<div class="mask" v-show="isShow">
<div class="window" v-if="isShow">
<p>弹窗内容</p>
<button @click="isShow = false">关闭弹窗</button>
</div>
</div>
</teleport>
setup() {
let isShow = ref(false)
return {
isShow
}
},
3.Suspense组件
<Suspense> 是一个内置组件,用来在组件树中协调对异步依赖的处理。它让我们可以在组件树上层等待下层的多个嵌套异步依赖项解析完成,并可以在等待时渲染一个加载状态。
使用步骤:
(1)异步引入组件
import { defineAsyncComponent } from 'vue'
// 引入异步组件
const child = defineAsyncComponent(() => import('./components/child.vue'))
(2)用Suspense组件将异步组件包裹,并配置default和fallback项
<Suspense> 组件有两个插槽:#default 和 #fallback。两个插槽都只允许一个直接子节点。在可能的时候都将显示默认槽中的节点。否则将显示后备槽中的节点。
在app.vue中:
<!-- suspense组件 等待异步组件时渲染一些额外内容 -->
<Suspense>
<template #default>
<child></child>
</template>
<template #fallback>
child组件加载中,请稍后
</template>
</Suspense>
在child组件中:
setup() {
// 异步两秒返回promise对象
return new Promise((resolve, rej) => {
setTimeout(() => {
resolve('wait')
}, 2000)
})
},
(七)其他改变
1.全局api的转移
vue2中常使用的全局api如config,direactive,component等,由原来的Vue.xxx的调用方法改为了vue3中的app.xxx(app是创建应用实例对象)
2.其他改变
(1)data配置项应始终被声明为一个函数
(2)过渡类名的修改
.v-enter ==> .v-enter-from
.v-leave==> .v-leave-from
(3)移除keyCode作为 v-on 的修饰符,同时也不再支持config.keyCodes
(4)移除v-on.native修饰符
(5)移除过滤器filter