温故知新,常看常记
setup 函数
参数一:props
props 是父组件传递过来的属性对象
1.对于props定义的类型,和vue2的规则是一样的,在props的选项中定义。
2.在template中也可以正常去用
参数二:context
context 也称之为是一个SetupContext,包含三个属性
- attrs:所有非props的attribute(自定义属性)
- slots: 父组件传递过来的插槽(render的时候用)
- emit: 当组件内部需要发出事件时会用到emit
App.vue
<template>
<home message = '哈哈哈'>
<template #default>
<h2>哈哈哈哈哈</h2>
</template>
</home>
</template>
<script>
import Home from './Home.vue'
export default{
components:{Home}
setup(){
}
}
</script>
Home.vue
<template>
</template>
<script>
export default{
props:{
message:{
type:String
}
},
//setup(props,context){
setup(props,{attrs,slots,emit}){
...
}
}
</script>
setup 函数的返回值
setup 的返回值:1.可以在模版template中使用;2.可以通过setup的返回值来替代data选项;3.也可以返回一个执行函数来替代methods中定义的方法。
<script>
const name = ' toamto '
let counter = 0
const increment = () => coutner++
const decrement = () => counter--
return {
name,
increment,
decrement
}
</script>
但是上面这种写法并不能实现界面的响应式,默认情况下Vue并不会跟踪一个定义的变量来更新界面
setup 不可以使用this
官方的描述:
- this并没有指向当前组件实例
- 并且在setup被调用之前,data、methods、computed等都没有被解析所以无法在setup中使用this
reactive API
如果想为在setup函数中定义的数据提供响应式的特性,可以使用reactive函数
import {reactive} from 'vue'
const state = reactive({
name:"tomato",
age:18
})
当我们使用reactive函数处理我们的数据之后,数据再次被使用时就会进行依赖收集,当数据发生改变时,所有收集到的依赖都会进行对应的响应式操作 (比如更新界面)。
事实上,我们编写的data选项,也是在内部交给了reactive函数将其变成响应式对象的。
reactive 补充的api
- isProxy 检查对象是否由reactive 或 readonly 创建的proxy
- isReactive
- 检查对象是否由reactive创建的
- 如果是readonly包裹了另一个reactive创建的响应式代理也返回true
- isReadonly检查对象是否由readonly创建
- toRaw 返回reactive 或readonly代理的原始对象
- shallowReactive : 创建一个响应式代理,跟踪其自身的property的响应性,但不执行嵌套对象的深层响应式转换(深层还是原声对象)
- shallowReadonly : 创建一个proxy,使其自身的property为只读,但不执行嵌套对象的深度只读转换(深层还是可读可写的)
ref API
reactive API 对传入的数据类型是有限制的,它要求我们必须传入的是一个对象或者数组类型。如果传入基本数据类型(string,number,boolean)会报警告。
“value cannot be made reactive:xxx"
这个时候Vue3提供了ref API:
- ref 会返回一个可变的响应式对象,该对象作为一个响应式的引用维护着它内部的值
- ref内部的值是在ref的value属性中被维护的
import { ref } from 'vue'
setup(){
const message = ref("Hello world")
return{ message }
}
⚠️注意
- 在template中引入ref的值时,vue会自动帮助我们进行解包,所以在模版中不需要通过ref.value 来使用
- 但是在setup函数内部,它依然是一个ref引用,所以对其进行操作时,还是要使用ref.value来操作它
ref 补充的api
- unref : 获取一个ref引用中的value,如果参数是一个ref,返回内部的值,否则返回参数本身
语法糖函数
val = isRef(val) ? val.value : val
const { name, age} = toRefs(obj);
unref(name) // tomato
- isRef 判断值是否是一个ref对象
- shallowRef 创建一个浅层的ref对象
- triggerRef 手动出发和shallowRef相关联的副作用
const info = shallowRef({name:"lili"})
// 下面的修改不再是响应式的了
const changeInfo = () => {
info.value.name = ' tomato'
//需要手动触发
triggerRef(info)
}
readonly
通过reactive 或者ref 可以获取到一个响应式的对象。但是某些情况下哎,我们传入给组件的这个响应式对象希望被其他的组件使用,但是不能被修改,这个时候就使用readonly
- vue3 位我们提供了readonly方法
- readonly会返回原生对象的只读代理(也就是它依然是一个Proxy,但是这个proxy的set方法被劫持,并且不能对其进行修改)
const infoProxy = new Proxy(info,{
get(target,key){
retirm target[key]
},
set(target,key,value){
warmomg("不允许修改不可变的值")
}
})
const name = infoProxy.name
infoProxy.name = 'tomato'
readonly传入的参数
- 类型一:普通对象
- 类型二:reactive返回的对象
- 类型三:ref返回的对象
readonly 使用规则
- readonly返回的对象都是不允许修改的
- 经过readonly处理的原对象是被允许修改的
const obj = {
name:"lili",
}
const readonlyInfo = readonly(boj) // readonlyInfo 对象不允许被修改
obj.name = 'tomato' // obj 可以修改,修改后readonlyInfo的值也会被更新
- 我们传递给其他组件数据时,不允许它们修改就用readonly
App.vue
<header :info = 'readonlyInfo" />
<home :info = 'info' />
<script>
import {reactive,ref,readonly} from 'vue'
export default{
components:{Header,Home},
setup(){
const info = reactive({
name:"tomato",
age:18
})
const readonlyInfo = readonly(info)
return {
info,
readonlyInfo
}
}
}
</script>
toRefs
- 如果我们使用ES6的解构语法,对reactive返回的对象进行解构获取值,数据会变成非响应式的
- 使用toRefs 让解构出来的属性变成响应式的
import {toRefs} from 'vue'
const {name,age} = toRefs(info)
return {
name,
age
}
toRef
只希望转换一个reactive对象中的属性
import {toRef} from 'vue'
const name = toRef(info,'name')
const {age} = info
const changeName = () => {
name.value = 'tomato'
或者
info.name = 'tomato'
}