程序猿要了3个孩子,分别取名叫Ctrl、Alt 和Delete,
如果他们不听话,程序猿就只要同时敲他们一下就会好的。
一 computed
1. 变成函数式了,不再和之前一样了,之前为一个对象
1.1 vue2 版本
var vm = new Vue({
data: { a: 1 },
computed: {
// 仅读取 不能直接修改
aDouble: function () {
return this.a * 2
},
// 读取和设置
aPlus: {
get: function () {
return this.a + 1
},
set: function (v) {
this.a = v - 1
}
}
}
})
vm.aPlus // => 2
vm.aPlus = 3
vm.a // => 2
vm.aDouble // => 4
1.2 vue3 版本
简写版本 仅读取 不能直接修改
接受一个 getter 函数,并根据 getter 的返回值返回一个不可变的响应式 `ref` 对象
const count = ref(1)
const plusOne = computed(() => count.value + 1)
console.log(plusOne.value) // 2
plusOne.value++ // 错误
在只读的情况下修改内容的话,会警告 写操作失败:计算值为只读
或者
接受一个具有 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
主要 以上都为 ref(Refimpl) 对象,都是需要进行 `.value` 的
在vue3中 新增了ts版本,这里就不写了 computedTs写法
总体来说 没什么特别大的变化,最大的变化还是语法上的变化
支持的新特性 获取上一个值
- 仅 3.4+ 支持
如果需要,可以通过访问计算属性的 getter 的第一个参数来获取计算属性返回的上一个值
<script setup>
import { ref, computed } from 'vue'
const count = ref(2)
// 这个计算属性在 count 的值小于或等于 3 时,将返回 count 的值。
// 当 count 的值大于等于 4 时,将会返回满足我们条件的最后一个值
// 直到 count 的值再次小于或等于 3 为止。
const alwaysSmall = computed((previous) => {
if (count.value <= 3) {
return count.value
}
return previous
})
</script>
二 watch 差异较大!
2.1 基本语法
2.1.1 侦听一个
watch数据源可以是一个具有返回值的 getter 函数,也可以直接是一个 ref
// 侦听一个 getter
const state = reactive({ count: 0 })
watch(
() => state.count,
(count, prevCount) => {
/* ... */
}
)
// 直接侦听一个 ref
const count = ref(0)
watch(count, (count, prevCount) => {
/* ... */
})
2.1.2 侦听多个
侦听多个的时候使用数组
const firstName = ref('')
const lastName = ref('')
watch([firstName, lastName], (newValues, prevValues) => {
console.log(newValues, prevValues)
})
firstName.value = 'John' // logs: ["John", ""] ["", ""]
lastName.value = 'Smith' // logs: ["John", "Smith"] ["John", ""]
!!!!! 多个同步更改只会触发一次
const changeValues = () => {
firstName.value = 'John'
lastName.value = 'Smith'
// 打印 ["John", "Smith"] ["", ""]
}
注意点 如果你在同一个函数里同时改变这些被侦听的来源,watch仍只会执行一次
官方的解决方法(不推荐):
使用 async await 关键字,并且使用 nextTick 等待watch在下一步改变之前运行
const changeValues = async () => {
firstName.value = 'John' // 打印 ["John", ""] ["", ""]
await nextTick()
lastName.value = 'Smith' // 打印 ["John", "Smith"] ["John", ""]
}
2.2 watch 特殊点 (主要是特殊的差异点为ref
和reactive
)
2.2.1 当wacth监听的为ref数据
const count = ref(0)
watch(count, (count, prevCount) => {
/* ... */
})
问题
一. 为什么这里的 ref 监听的时候不需要.value
呢?那么.vaule
又是为什么
答:
首先知道 我们通过 ref 声明的基本数据类型,会被改造成 refImpl 对象
那么.value 相当于 拿到了这个基本数据类型 0
但我们的wacth监听的根本不是这个基本数据类型,监听而是通过ref改造过后的 refImpl 对象
2.2.2 当wacth监听的为reactive数据
监听的数据为reactive声明的整个
const info = reactive({
name:'张三',
age:18,
obj:{
a:{
b:10
}
}
})
watch(info, (newValues, prevValues) => {
console.log(newValues, prevValues) // 打印 为同一个info 没有区分改变前和改变后的变化 ,均为改变后的值
}, {deep:fales}) // deep 无效
总结 问题
- 无法正确的获取改变前的值,newValues, prevValues打印结果均为改变后的值
- deep为fales无效,相当于强制开启了deep,并且无法关闭。
- 解决方案 watch监听的数据为一个数组形式的 getter 函数
但是
当你监听info中的obj时
watch(info.obj, (newValues, prevValues) => {
console.log(newValues, prevValues)
}, {deep:true}) // deep 生效
总结 问题
1 当watch监听的数据为reactive中的一个对象属性时,deep是可以正常生效的 (疑问?为什么呢)