Vue3.0
发布了很多新的特性和一些语法上的变更。其中 Composition API
是Vue3.0
版本中主要特色语法,这是一个全新的逻辑重用和代码组织的方法。这边文章就带你看看为啥会有Composition API
以及如何使用Composition API
Option API 和 Composition API 的比较
我们知道Vue2.0
(选项)所有数据都定义在data
中,方法定义在methods
中。所以给组件添加逻辑, 我们可能需要填充(选项)属性data
, methods
,computed
等。但是Vue3.0
我们可以不这么写了。具体怎么写, 我们先看看Vue2.0
的写法有什么缺陷。
Option API
使用Vue2.0
的option API
实现如下功能:
我们实现一个加减法,之后数值显示出来,就需要分别在data
,computed
,methods
添加代码,如果还有其他功能,可能还得在生命周期选项等添加代码。那如果需要添加其他的需求。我们的代码结构可能就变成这样了:
Composition API
在Vue3.0
中, 我们可以使用Composition API
的方式来实现:
代码按照逻辑(Composition API
的方式来实现)来分割,上面的图变成下面的图(相同业务逻辑的代码颜色),是不是就清晰了?
可以看的出来: Option API
相同业务的代码分散在各处,这样后期维护起来就很麻烦。而Composition API
就解决了这个问题。那么下面就来讲解Composition API
怎么使用。
Composition API 的入口及API
关于Composition API
有哪些API
呢? 先总结一下:
下面根据这些知识点分别来讲解。
setup
setup
功能是新的组件选项,是Composition API
使用的入口。
执行的的时机
setup
是在创建vue
组件实例并完成props
的初始化之后执行(在beforeCreate
钩子之前执行)。这就直接限制了在setup
中无法使用其他的选项(option
)中的数据;如:data
,methods
,computed
等。 但是其他的选项(option
)可以使用setup
中返回的变量。
由于在执行
setup
函数的时候,还没有执行Created
生命周期方法,所以在setup
函数中,无法使用data
和methods
的变量和方法
1 | export default { |
打印的结果为:
setup中的上下文
setup
中是没有this
上下文的.为什么呢? javascript
函数中都是应该有this
。但是由于 执行的的时机的原因,setup
中的this
与Vue2.x
中的this
已经不是一个东西了。所以为了防止错误的使用,直接将this
改成了 undefined
。
由于我们不能在
setup
函数中使用data
和methods
,所以 Vue 为了避免我们错误的使用,直接将setup
函数中的this
修改成了undefined
1 | export default { |
与模板的使用
setup
如果返回的是一个对象的话,那么这个对象的所有属性会合并到template
的渲染上下文中(也就是说可以在template
中使用setup
的返回的对象的属性)。
在template
中,vue
已经帮我们自动获取value
属性, 所有我们只需要{{ people.name }}
,{{ people.age }}
,{{ sex }}
参数
setup
是一个函数,它接受两个参数:props
,context
下面我们一个具体的例子项目来讲解。假如我们有这样的项目:
props
props
是父组件传给子组件或者vue-router
传给页面的参数。setup
中的props
是响应式,当传入新的props
,就会被更新。
1 | export default { |
注意: 因为
props
是响应式的, 所以不能使用ES6
解构,如果这样做将会失去响应性。
如果需要ES6
解构并且需要数据的响应性的的话, 可以使用toRefs
来完成。下面也会讲到。
1 | import { toRefs } from "vue" |
context
context
是一个javascript
对象,它暴露了3 个property
:attrs
、slot
和emit
。分别对应Vue2.x
的$attr
属性、slot
插槽 和$emit
。
1 | export default { |
props
和 context
具体的代码如下:
ref
ref
函数接受一个值,用于初始化的值,然后返回一个响应式且可修改的ref
对象。该对象有一个value
属性。valus
保存ref
对象的值。所以修改变量的话需要修改变量的value
值。
1 |
|
我们看看这段代码打印的结果:
说明:
- 使用
ref
初始化的变量都是一个对象(ref
函数接受一个值,用于初始化的值,然后返回一个响应式且可修改的ref
对象)。valus
保存ref
对象的值。 - 在
setTimeout
时候, 想要修改people
这个响应式对象的值,则需要通过赋值操作people.value.name = "zhangdada"
来实现。
再继续看视图页面
## reactivereactive
和ref
很相似。 也是一个函数,但是只接受一个对象。并返回一个对这个对象的响应式代理
1 | import { reactive, toRefs } from "vue"; |
我们看打印的结果:
再看看template
中的使用:
最后可得出结论:
reactive
函数返回一个对这个对象的响应式代理reactive
可以将零散的变量聚焦在一个对象reactive
中的变量的取值和赋值不需要取其value
值
注意的点:使用reactive
时记得使用toRefs
保证reactive
对象属性保持响应性。
isRef
isRef
用于判断变量是为ref
对象
1 | import { ref, reactive, isRef } from "vue"; |
toRefs
toRefs
用于将一个reactive
对象转化为属性为ref
对象的普通对象。
1 | export default { |
watch
watch
与选项式API
(this.$watch/watch
选项)完全等效的。watch
需要监听特定的data
数据源,并且在单独的回调函数中副作用。默认的情况下,是惰性的,也就是说回调函数仅在监听源数据发生变更时才会回调。
语法:
1 | watch(source, callback, [options]) |
参数说明:
source:
要监听的响应式变量。支持String
,Object
,Function
,Array
。callback
: 要执行的回调函数。回调函数的第一个参数是监听的数据更新后的值, 第二个参数之前监听的数据之前得值。options
: 支持deep、immediate 和 flush 选项。- 当我们监听复杂的嵌套数据对象的时候,需要传入第三个参数的
deep:true
。这个参数的意思是进行深拷贝,目的是为了真正的监听复杂数据对象 - 希望
watch
不是惰性的(立即执行回调函数)可以设置immediate: true
- 当我们监听复杂的嵌套数据对象的时候,需要传入第三个参数的
监听ref
定义的数据
1 | import { ref, watch } from "vue"; |
监听reactive
定义的数据
1 |
|
监听多个数据
1 | import { ref, watch } from "vue"; |
监听复杂的嵌套数据
1 | import { watch, reactive} from "vue"; |
注意:当我们监听复杂的嵌套数据对象的时候,需要传入第三个参数的deep:true
。这个参数的意思是进行深拷贝,目的是为了真正的监听复杂数据对象。
设置watch
为立即执行
设置watch
的第三个参数:immediate: true
。 则watch
不是惰性的,即立即执行回调函数。
1 | import { watch, ref } from "vue"; |
停止监听
组件中创建的watch
监听,会在组件被销毁的时候自动停止,如果在组件销毁之前我们想停止某个监听,可以调用watch()
函数的返回值。
1 | import { watch, ref } from "vue"; |
结果: 不会监听到变化了
不能监听非响应式的值
1 | // 不能监听非响应式的值 |
watchEffect
watchEffect
和watch
类似,不过watchEffect
函数会自动收集依赖。 只需要指定一个回调函数。在组件初始化的时候,会先执行一次手机依赖。然后当收集到的依赖中数据发生变化时,会再次执行回调函数。有以下特点:
watchEffect
不需要手动传入依赖(不需要手动传入需要监听的值);watchEffect
会先执行一次用来自动收集依赖;watchEffect
无法获取到变化前的值,只能获取到变化后的值
1 | import { ref, watchEffect } from "vue"; |
结果可以看出来:组件初始化的时候先执行一次回调函数,收集依赖。1秒之后,依赖发生变化。回调函数会再次被调用。
停止监听
跟watch
的停止监听一样。组件中创建的watchEffect
监听,会在组件被销毁的时候自动停止,如果在组件销毁之前我们想停止某个监听,可以调用watchEffect()
函数的返回
1 | import { ref, watchEffect } from "vue"; |
回调函数只会在组件初始化的时候回调一次。因为停止了监听stop();
所以依赖发生了变化也不会再触发回调了。
不能监听非响应式的值
1 | { |
computed
computed
函数与Vue.x
的中的computed
功能一样。computed
接受一个函数并返回一个value
值为getter
返回值不可改变的响应式ref
对象。
1 | import { ref, computed, isRef } from "vue"; |
readonly
readonly
获取一个对象(响应式/纯对象)并返回原始代理的只读代理,只读代理是深层次的:访问的任何嵌套的property
也是只读的。返回的代理对象不可改变。但是传入的原始对象改变时,返回的代理对象也会相应的改变。如果传入的是ref
对象或者reactive
对象。那么返回的代理对象也是响应式的。
readonly 响应式对象
ref对象
1 | import { ref, readonly } from "vue"; |
reactive对象
1 | import { readonly, reactive } from "vue"; |
重要:readonly
响应式对象.只读代理是具有响应性的:
readonly 普调对象
1 | import { readonly } from "vue"; |
readonly 一个非对象
1 | import { readonly } from "vue"; |
生命周期
Composition API
有人提供了组件生命周期的钩子回调。我们先看vue3.0
生命周期图:
我们可以看出,vue3.0
增加了setup
,然后为了更加语义化将beforeDestroy
改成了beforeUnmount
;destotredy
改成了unmounted
。其他Vue2
中的生命周期仍然保留。这个图没有显示全部的声声明周期。我们看看全部的生命周期的钩子图示。
beforeCreate
和created
被setup
替换了(但是Vue3中你仍然可以使用, 因为Vue3是向下兼容的, 也就是你实际使用的是vue2的)。钩子命名都增加了on
; Vue3.x还新增用于调试的钩子函数数onRenderTriggered
和onRenderTricked
1 |
|
最后
当然关于Composition API
的还有很多的钩子,具体可以看中文官网 组合式 API? 英文官网:Composition API?
最后关于以上的例子的github
链接: vue3.0–Composition-API
通过修改src/main.js
中的不同的模板来看不同的API 示例
。