defineProps:
defineProps与props的区别是:前者用于setup单文件,后者用于组合式API
import { reactive, defineProps, defineEmits, watch, ref } from 'vue'
const props = defineProps({
dialogAddVisible: {
type: Boolean, default: false
}
item:[String, Number] // prop多个可能的类型
propE: { type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () { return { message: "hello" };},},
})
watch
第三个参数可以是
- { deep: true }:强制转成深层侦听器,当用于大型数据结构时,开销很大。因此请只在必要时才使用它 或
- { immediate: true}:强制侦听器的回调立即执行 或
- { flush:‘pre’ | ‘post’ | ‘sync’ //默认:‘pre’ }
(post:在侦听器回调中能访问被 Vue 更新之后的 DOM,watchPostEffect():watchEffect() 使用 flush: ‘post’ 选项时的别名;
watchSyncEffect():watchEffect() 使用 flush: ‘sync’ 选项时的别名。
监听ref数据,
watch(isDialogAddVisible, (val, old) => {
console.log(emit)
}, { deep: true })
监听多个
const firstName = ref('')
const lastName = ref('')
watch([firstName, lastName], ([newFirstName, newLastName],[oldFirstName, oldLastName]) => {
console.log(newFirstName, newLastName)
console.log(oldFirstName, oldLastName)
})
firstName.value = 'John' // logs: ["John", ""] ["", ""]
lastName.value = 'Smith' // logs: ["John", "Smith"] ["John", ""]
监听reactive单个数据
const state = reactive({ count: 0 })
watch(() => state.count, (val, old) => {})
watch不能直接监听一个数值,会报警告:Invalid watch source: 60 A watch source can only be a getter/effect function, a ref, a reactive object, or an array of these types
你不能直接侦听响应式对象的属性值,例如:
const obj = reactive({ count: 0 })
// 错误,因为 watch() 得到的参数是一个 number
watch(obj.count, (count) => {
console.log(`count is: ${count}`)
})
这里需要用一个返回该属性的 getter 函数:
// 提供一个 getter 函数
watch(
() => obj.count,
(count) => {
console.log(`count is: ${count}`)
}
)
或者:
const num = ref(0)
watch(num, (val, old) => { // 不使用num.value
console.log(val, old)
})
onInvalidate
解决竞态问题:watch函数的回调函数接收第三个参数onInvalidate,它是一个函数,类似于事件监听器,可以使用onInvalidate函数注册一个回调,这个回调函数会在当前副作用函数过期时执行
watch(obj, async (newValue, oldValue, onInvalidate) => {
// 定义一个标志,代表当前副作用函数是否过期,默认为 false,代表没有过期
let expired = false
// 调用 onInvalidate() 函数注册一个过期回调
onInvalidate(() => {
// 当过期时,将 expired 设置为 true
expired = true
})
// 发送网络请求
const res = await fetch('/path/to/request')
// 只有当该副作用函数的执行没有过期时,才会执行后续操作。
if (!expired) {
finalData = res
}
})
computed
只读的:
const countReadonly = ref(1)
const plusOneReadonly = computed(() => countReadonly.value + 1)
console.log(plusOneReadonly.value) // 2
plusOneReadonly.value++ // 错误
可写的:
const count = ref(1)
const plusOne = computed({
get: () => count.value + 1,
set: (val) => {
count.value = val - 1
}
})
function setComputed() {
plusOne.value = 1
}
stop停止监听
const state = reactive({ count: 0 })
const stopWatch = watch(() => state.count, (newType, oldType) => {
console.log("新值:", newType, "老值:", oldType);
}, {deep:true})
setTimeout(()=>{ // 停止监听
stopWatch()
}, 3000)
watchEffect
不需要手动传入依赖
会先执行一次用来自动收集依赖
无法获取到变化前的值, 只能获取变化后的值
const state = reactive({ count: 0, name: 'zs' })
watchEffect(() => {
console.log(state.count)
console.log(state.name)
})
await
顶级等待可以在<脚本设置>中使用。生成的setup()函数将被设置为异步:
<script setup>
const post = await fetch(`/api/post/1`).then((r) => r.json())
</script>
ref reactive toRefs toRefs之间的关系
- ref/reactive可触发页面改变
- toRefs toRef不可触发页面改变
- 只有toRefs支持解构
- ref可用于任何类型的数据创建响应式,reactive只用于创建引用数据类型的响应式(对于基本类型ref的性能优于reactive)
<template>
<div class="homePage">
<p>第 {{ year }} 年</p>
<p>姓名: {{ nickname }}</p>
<p>年龄: {{ age }}</p>
</div>
</template>
<script setup>
const year = ref(0)
const user = reactive({ nickname: "xiaofan", age: 26, gender: "女" })
setInterval(() => {
year.value++;
user.age++;
}, 1000);
</script>
toRefs:
用于将一个reactive对象转化为属性全部为ref对象的普通对象
ref:
一般用于基本类型
可直接赋值为空
官网链接:https://cn.vuejs.org/guide/essentials/reactivity-fundamentals.html#reactive-variables-with-ref
$ref语法糖(仍处于实验性阶段,在最终提案落地前仍可能发生改动)
vite.config.js中启用:
plugins: [vue({reactivityTransform: true})]
使用:
<script setup>
const testAge = $ref('0')
console.log(testAge)
</script>
reactive:
一般用于对象
不可直接赋值为[]等,需:Object.keys(obj).forEach(key => delete obj[key]})
shallowRef
修改深层属性时,并不会更新视图.想要更新视图,必须给value赋值,直接替换整个对象。或者在修改了数据之后,调用triggerRef方法,主动触发视图刷新