Vue 学习笔记11:Vue3组合API
一、创建 Vue3 工程
1. 使用 vue-cli 创建
- 查看 vue-cli 版本,确保在 4.5.0 以上
vue -V
- 如果版本没有高于 4.5.0 就重新安装 vue-cli
2. 使用 vite 创建
## 创建工程
npm init vite-app 工程名称
## 进入工程目录
cd 工程名称
## 安装依赖
npm i
## 运行
npm run dev
3. 安装 vue3 插件
点击第一个,添加到 Chrome
二、常用 composition API
1. setup 函数
- setup 是所有 Composition API(组合API)“表演的舞台”
- 组件中所用到的:数据、方法等等,均要配置在 setup 中
- setup 函数的两种返回值:
- 若返回一个对象,则对象中的属性、方法,在模板中均可直接使用(常用)
- 若返回一个渲染函数,则可以自定义渲染内容。
- 注意点:
- 尽量不要与 Vue2 配置混用
- setup 不能是一个 async 函数
2. ref 函数
- 作用:定义一个响应式的数据。
- 语法:
const xxx = ref(initvalue)
- 创建一个包含响应式数据的【引用对象】(reference对象,简称ref对象)
- JS 中操作数据:
xxx.value
- 模板中读取数据:
<div>{{xxx}}</div>
- 备注:
- 接收的数据可以是:基本类型,也可以是对象类型。
- 基本类型的数据:响应式依然是依靠
Object.defineProperty()
的get
和set
- 对象类型的数据:内部求助了 Vue3 中的一个新函数
reactive()
3. reactive 函数
- 作用:定义一个【对象类型】的响应式数据(基本类型不要用它,要用
ref
函数) - 语法:
const 代理对象 = reactive(源对象)
接收一个对象(或数组),返回一个代理对象(Proxy 的实例对象,简称 Proxy 对象) - reactive 定义的响应式数据是“深层次的”
- 内部给予 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据进行操作。
4. Vue3 的响应式
- 通过 Proxy(代理):拦截对象中任意属性的变化,包括属性值的读写、添加、删除。Object.defineProperty() 只能拦截读写。
- 通过 Reflect(反射):对源对象的属性进行操作,返回布尔值,代表是否操作成功。
new Proxy(data, {
// 拦截读取属性值
get(target, prop){
return Reflect.get(target, prop)
},
// 拦截设置属性值或添加新属性
set(target, prop){
return Reflect.set(target, prop, value)
}
// 拦截删除属性
deleteProperty(target, prop){
return Reflect.deleteProperty(target, prop)
}
})
5. reactive 对比 ref
- 从定义数据角度对比:
ref 用来定义:【基本类型数据】
reactive 用来定义:【对象或数组类型数据】
备注:ref 也可以用来定义对象或数组类型数据,它内部会自动通过 reactive 转为代理对象
- 从原理角度对比:
ref 通过
Object.defineProperty()
的 get 与 set 来实现响应式(数据劫持)。
reactive 通过使用Proxy
来实现响应式,并通过Reflect
操作源对象内部的数据。
- 从使用角度对比:
ref 定义的数据:操作数据需要
.value
,读取数据时模板中直接读取不需要.value
reactive 定义的数据:操作数据与读取数据,均不需要.value
6. setup 的两个注意点
- setup 执行的时机:在 beforeCreate 之前执行一次,this 是 undefined。
- setup 的参数
-
props:值为对象,包含:组件外部传递过来,且组件内部声明接受了的属性。
-
context:上下文对象
attrs:值为对象,包含:组件外部传递过来,但没有在 props 配置中声明的属性,相当于
this.$attrs
slots:收到的插槽内容,相当于this.$slots
emit:分发自定义事件的函数,相当于this.$emit
7. 计算属性与监视
(1)computed 函数
- 与 Vue2 中的 computed 配置功能一样
- 写法
import { computed } from 'vue'
setup(){
...
// 计算属性——简写(没有考虑计算属性被修改的情况)
let fullName = computed(() => {
return person.firstName + '-' + person.lastName
})
// 计算属性——完整
let fullName = computed({
get(){
return person.firstName + '-' + person.lastName
},
set(value){
const nameArr = value.split("-")
person.firstName = nameArr[0]
person.lastName = nameArr[1]
}
})
(2)watch 函数
-
与 Vue2 中的 watch 配置功能一致
-
两个小坑:
监视 reactive 定义的响应式数据时:oldValue 无法正确获取、强制开启了深度监视(deep 配置失效)
监视 reactive 定义的响应式数据中某个属性时:deep 配置有效。
// 情况一:监视【一个】 ref 定义的响应式数据
watch(sum, (newValue, oldValue) => {
console.log('sum变化了', newValue, oldValue)
}, {immediate: true})
// 情况二:监视【多个】 ref 定义的响应式数据
watch([sum, msg], (newValue, oldValue) => {
console.log('sum 和 msg 变化了', newValue, oldValue)
})
// 情况三:监视 reactive 定义的响应式数据,无法正确获得 oldValue,强制开启深度监视
watch(person, (newValue, oldValue) => {
console.log('person 变化了', newValue, oldValue)
}.{immediate: true, deep: false}) // 此处的 deep 配置失效
// 情况四:监视 reactive 定义的响应式数据中的【某个】属性
watch(() => person.job, (newValue, oldValue) => {
console.log('person的job变化了', newValue, oldValue)
}.{immediate: true, deep: true}) // 此处的 deep 配置奏效
// 情况五:监视 reactive 定义的响应式数据中的【某些】属性
watch([() => person.name, () => person.age], (newValue, oldValue) => {
console.log('person的name或age变化了', newValue, oldValue)
})
(3)watchEffect 函数
- watch 的套路是:既要指明监视的属性,也要指明监视的回调。
- watchEffect 的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性。
- watchEffect 有点像 computed:
但 computed 注重的计算出来的值(回调函数的返回值),所以必须要写返回值。
而 watchEffect 更注重的是过程(回调函数的函数体),所以不用写返回值。
// watchEffect 所指定的回调中用到的数据只要发生变化,则直接重新执行回调
watchEffect(() => {
const x1 = sum.value
const x2 = person.name
console.log("watchEffect配置的回调执行了")
})
8. Vue3 生命周期
新的生命周期钩子
-
Vue3 中可以继续使用 Vue2 中的生命周期钩子,但有两个被更名:
beforeDestory
改名为beforeUnmounted
destory
改名为unmounted
-
Vue3 也提供了 Composition API 形式的生命周期钩子,与 Vue2 中的钩子对应如下:
beforeCreate ===> setup()
create ===> setup()
beforeMount ===> onBeforeMount
mounted ===> onMounted
beforeUpdate ===> onBeforeUpdate
updated ===> onUpdate
beforeUnmount ===> onBeforeUnmount
unmounted ===> onUnmounted -
Vue2 中的
beforeCreate
和create
不能写进 setup 中 -
setup 中的钩子比 Vue2 中的钩子优先级高
9. 自定义 hook 函数
- 什么是 hook?——本质是一个函数,把 setup 函数中使用的 Composition API 进行封装。
- 类似于 Vue2 中的 mixin
- 自定义 hook的优势:代码复用,让 setup 中的逻辑更清楚易懂。
10. toRef
- 作用:创建一个 ref 对象,其 value 值指向另一个对象中的某个属性
- 语法:
const name = toRef(person, 'name')
- 应用:要将响应式对象中的某个属性单独提供给外部使用时。
- 扩展:
toRefs
与toRef
功能一致,但可以批量创建多个 ref 对象,语法:toRefs(person)