在基础的响应式数据和事件函数之后,我们再来说说 computed 计算属性 和 watch 监听吧。
通过数据和事件处理的几个例子,大家或许发现了 Vue3 的两个基本变化思路:
而这两者都避免了再将各种不同层级的属性、方法绑定到 $vm 上,从而避免了混乱的 this
指向问题。
以至于我们在 Vue3 的例子里基本没再用到过 this
。
对于父级组件传入的属性值,以前都是通过 this.<属性名>
访问的,在 Vue3 的 setup()
中怎么获取组件属性呢?
很简单,setup()
函数收到的第一个参数就是传入的属性值了:
export default {
props: {
name: String,
},
setup(props) {
const { name } = props;
return { name };
},
};
不过由于传入的 props
是一个响应式数据,为了确保传入的非引用型数据发生变化时,页面内状态能动态更新,我们还得用 toRefs
从里面解构取值:
import { toRefs } from 'vue';
export default {
props: {
name: String,
},
setup(props) {
const { name } = toRefs(props);
return { name };
},
};
对于间接通过其它数据再计算出来的计算属性,通过 Vue3 的组装 API 实现也很简单:
// sells.js
import { ref, toRefs, computed } from 'vue';
export default {
props: {
// 库存数量
totalCount: Number,
// 售出数量
sellCount: Number,
},
setup(props) {
const {
totalCount = ref(0),
sellCount = ref(0),
} = toRefs(props);
// 剩余数量
const remainCount = computed(() => totalCount.value - sellCount.value);
return { totalCount, sellCount, remainCount };
},
};
除了实际的业务逻辑之外,computed() 通常还可以用于多个 className 的计算合成,比如:
export default {
props: {
// 是否禁用状态
disabled: Boolean,
},
setup(props) {
const { disabled } = toRefs(props);
const className = computed(() => [
'sells-list',
{
'is-disabled': disabled,
},
]);
},
};
当某个响应数据发生变化时,执行相关处理逻辑,我们就会用到 watch() 了:
const { disabledIds } = toRefs(props);
const selectedId = ref(null);
// 监听某个数据
watch(selectedId, (val, oldVal) => {
// do something
});
// 监听多个数据
watch([selectedId, disabledIds], (val, oldVal) => {
// 此时传入的 val 和 oldVal 将会是多个数据的数组
});
// 监听某个复合条件的结果
watch(() => selectedId === disabledIds, (val, oldVal) => {
// 当其中相关值发生改变,但结果不变时,这里不会被触发
});
我们还可以使用 watch() 返回的停止器来结束监听:
const selectedId = ref(null);
const stopWatch = watch(selectedId, (val) => { });
stopWatch();
与 watch 不同,watchEffect() 不需要指明监听目标,在它接收一个 effect 函数后,将会立刻执行并分析其中依赖的响应数据,在它们发生变化时再次执行这个 effect 函数。:
const sellsCount = ref(0);
watchEffect(() => {
console.log(`sellsCount: ${sellsCount.value}`);
});
// 将会立刻看到输出日志,之后数据变化时再次打印日志
如果需要在监听停止的同时,做一些额外的回收处理(比如解除 DOM 事件监听器、清理其它数据等),可以用到 onInvalidate 函数:
const sellsCount = ref(0);
watch(sellsCount, (val, oldVal, onInvalidate) => {
console.log(`sellsCount: ${val}`);
onInvalidate(() => {
// 回收处理
});
});
watchEffect((onInvalidate) => {
console.log(`sellsCount: ${sellsCount.value}`);
onInvalidate(() => {
// 回收处理
});
});