前言
最近公司正式将Vue3.0作为前端框架,自己也参与了2个Vue3.0项目的开发,所以准备出一个Vue3.0的学习系列,提到Vue3.0,就不得不说composition API
,所以本文就作为Vue3.0系列的开篇之作。
解决什么痛点?
使用过Vue2.0通常知道,用(data、computed、methods、watch
)组件选项来组织逻辑很有效,然而,随着组件变大,逻辑复制时,导致组件难以阅读合理解和后续维护性非常复杂,特别是接手别人代码时,往往需要来回跳转阅读。基于此composition api
应用而生。对比图如下:
setup
新的setup
选项在组件创建之前执行,一旦props
被解析,就将作为Composition API
的入口。
setup中避免使用this,因为无法获取组件实例;同理,setup的调用发生在data、property、computed property、methods被解析之前,同样在setup中无法获取。
setup接收两个参数:
props
(props是响应式的,不能使用ES6解构,如需解构使用toRefs
或toRef
)context
(普通对象,可解构,包含3个属性。context.attrs、context.slots、context.emit
)
import { toRefs,roRef } from 'vue'
props: {
name: String,
age: Number
},
setup(props,context){
console.log(props.name)
//toRefs 不会创建一个 ref ,而toRef 可以:
const {name}=toRefs(props)
const {age}=toRef(props,'age')
// Attribute (非响应式对象)
console.log(context.attrs)
// 插槽 (非响应式对象)
console.log(context.slots)
// 触发事件 (方法)
console.log(context.emit)
}
复制代码
结论
执行 setup
时,组件实例尚未被创建。因此,你只能访问以下 property:
props
attrs
slots
emit
换句话说,你将无法访问以下组件选项:
data
computed
methods
ref 与 reactive
在vue3中,官方提供了ref()
与reactive()
两种方式声明响应式数据,接下来我们将详细介绍各自的用法以及两者的区别。
ref函数
接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象具有指向内部值的单个 property .value
import { ref } from 'vue'
const age = ref(0)
console.log(age.value) // 0
age.value++
console.log(age.value) // 1
复制代码
而为何将值封装到一个对象里面?
官方给出了分析和解释:
在 JavaScript 中,
Number
或String
等基本类型是通过值而非引用传递的。封装成对象,这样我们就可以在整个应用中安全地传递它,而不必担心在某个地方失去它的响应性。
结论
ref
为我们的值创建了一个响应式引用
reactive函数
返回对象的响应式副本,响应式转换是“深层”的——它影响所有嵌套 property。
import { reactive } from 'vue'
const obj=reactive({
name:'Vue3',
age:1
})
复制代码
reactive
将解包所有深层的 refs,同时维持 ref 的响应性。
const age = ref(1)
const obj = reactive({ age })
// ref 会被解包
console.log(obj.age === age.value) // true
// 它会更新obj.age
age.value++
console.log(age.value) // 2
console.log(obj.age) // 2
// 它也会更新 age ref
obj.age++
console.log(obj.age) // 3
console.log(age.value) // 3
复制代码
当将 ref 分配给 reactive
property 时,ref 将被自动解包。
const age = ref(1)
const obj = reactive({})
obj.age = age
console.log(obj.age) // 1
console.log(obj.age === age.value) // true
复制代码
区别
reactive 和 ref 都是用来定义响应式数据的 reactive更推荐去定义复杂的数据类型, ref 更推荐定义基本类型
ref 和 reactive 本质我们可以简单的理解为ref是对reactive的二次包装, ref定义的数据访问的时候要多一个.value
使用ref定义基本数据类型,ref也可以定义数组和对象。
reactive 不能代理基本类型,例如字符串、数字、boolean 等
toRef与toRefs
前面我们提到Props不能使用使用ES6解构,同样,响应式对象也不能使用ES6解构,但是我们想要解构但有不要失去响应怎么办?这个时候toRef或toRefs就来了。
toRef 可以用来为源响应式对象上的某个 property 新创建一个 ref
。
toRefs 用于将一个 reactive 对象转化为属性全部为 ref 对象的普通对象。
import { defineComponent, reactive, toRefs, toRef } from "vue";
export default defineComponent({
setup () {
const person = reactive({
name: 'icey',
age: 18,
height: 160
})
const ageRef = toRef(person, 'age')
const { age } = toRefs(person)
ageRef.value++
console.log(person.age) // 19
console.log(age.value) //19
person.age++
console.log(ageRef.value) // 20
console.log(age.value) //20
}
})
复制代码
区别
toRef
会为源对象不存在的 property生成ref。toRefs
只会为源对象中包含的 property 生成 ref。
当你要将 prop 的 ref 传递给复合函数时,toRef
很有用:
即使源 property 不存在,toRef
也会返回一个可用的 ref。这使得它在使用可选 prop 时特别有用。
computed、watch 与watchEffect
computed 计算属性
- 接受一个 getter 函数,并为从 getter 返回的值返回一个不变的响应式
ref
对象。
import { defineComponent, computed, ref } from "vue";
export default defineComponent({
setup () {
const count = ref(1)
const plusOne = computed(() => count.value + 1)
console.log(plusOne.value) // 2
plusOne.value++
console.log(plusOne.value) // 2
}
})
复制代码
- 使用具有
get
和set
函数的对象来创建可写的 ref 对象。
const count = ref(1)
const plusOne = computed({
get: () => count.value + 1,
set: val => {
count.value = val - 1
}
})
plusOne.value = 1
console.log(count.value) // 0
复制代码