有时候在vue3开发中,有些情况我们不知道是使用Computed
还是使用Ref
比较好,虽然两者都能实现功能。本文我们来探讨一下两者的差异。
计算属性(Computed)是一种基于响应式依赖关系进行缓存运算的属性。当它的依赖关系发生改变时,它就会重新求值。并且只有在它的相关依赖项发生改变时才会重新计算,否则,它会立即返回之前的计算结果,这有利于提高性能。
响应式引用(Ref)是Vue 3的新特性。它可以让我们在任何地方使用响应式数据,包括不是响应式对象的地方。Ref创建的变量被包装在一个响应式对象中,当值改变时,视图会自动更新。
比如下面的例子,可以实现一个显示帖子和点赞数量的组件:
//子组件
<template>
<div class="post-container">
<div class="post-footer">
<span class="post-likes">Likes:</span>
{{ likesRef }} <!-- 或者 likesComputed? -->
<button class="post-like-button">👍</button>
</div>
</div>
</template>
<script setup>
import { ref, toRefs, watch, computed } from 'vue'
//假设有个post对象
const props = defineProps({
post: {
required: true,
type: Object,
}
})
// 可以使用ref,创建一个新的响应式引用likesRef,它的值为post.likes。
const likesRef = ref(props.post.likes)
// 也可以使用computed, 创建一个计算属性likesComputed,它的值是基于post.likes的值动态计算出来的。
//这里,计算属性的计算函数是一个返回post.likes值的箭头函数。
const likesComputed = computed(() => props.post.likes)
</script>
使用子组件:
<script setup lang="ts">
import Flow from "@/components/Flow.vue";
import {ref} from "vue";
const post = ref({likes: 123,content:'哈哈哈哈'})
</script>
<template>
<Flow :post="post"></Flow>
</template>
这两种方式都是可以正确的显示点赞数量的。
那假设你想在一个获得1000个赞的帖子上显示一个星形"⭐️"。
你会用哪一种方式来实现呢?
- 使用ref实现
//子组件
<template>
<div class="post-container">
<div class="post-footer">
<span class="post-likes">Likes:</span>
{{ likes }}
<button class="post-like-button">👍</button>
<!-- 点赞超过1000就显示⭐️ -->
<span v-if="thousandLikes" class="post-star-icon">⭐️</span>
</div>
</div>
</template>
<script setup>
import { ref, toRefs, watch, computed,watchEffect } from 'vue'
const props = defineProps({
post: {
required: true,
type: Object,
}
})
const likes = ref(props.post.likes)
const thousandLikes = ref(false)
watchEffect(() => {
if (likes.value >= 1000) {
thousandLikes.value = true
}
})
</script>
在这里,watchEffect
用于监视 likes
引用的值。当 likes
的值发生变化时(例如,从用户的交互中增加或者减少 likes),它就会立即触发内部的函数运行。
- 使用computed实现 使用computed只需要写一行代码:
const likes = ref(props.post.likes)
const thousandLikes = computed(() => {
return likes.value >= 1000
})
使用ref
或者computed
,都可以显示出⭐️。
现在我们加一个按钮来控制⭐️的隐藏。
//省略
<span v-if="thousandLikes" class="post-star-icon">⭐️</span>
<button
@click="thousandLikes = false"
class="post-hide-star"
>
隐藏星星
</button>
//省略
使用ref
是可以实现隐藏⭐️的,因为thousandLikes
(ref)是一个响应式属性,可以在任何地方更新其值。
但是,如果你尝试更新 thousandLikes
(computed),Vue要么会抛出一个警告,要么你的组件会崩溃。这是因为computed
属性是只读的。你可以更新它的依赖项,但不能直接更新最后的结果。
如果你想使用computed
,你需要在组件中添加另一个属性:
<template>
<div class="post-container">
<div class="post-footer">
<span class="post-likes">Likes:</span>
{{ likes }}
<button class="post-like-button">👍</button>
<!-- 点赞超过1000就显示⭐️ -->
<span v-if="thousandLikes" class="post-star-icon">⭐️</span>
<button
@click="hideStar = true"
class="post-hide-star"
>
隐藏星星
</button>
</div>
</div>
</template>
<script setup>
//省略
const hideStar = ref(false)
const thousandLikes = computed(
() => {
return likes.value >= 1000 && !hideStar.value
}
)
</script>
总结
ref
属性是可变的响应式属性,并且只能通过向其传递对象来设置,而不能进行操作。computed
属性是对响应式属性进行的操作,而computed
属性本身是只读的;
在实际使用中,如何选择使用计算属性还是响应式引用,取决于你的具体需求。计算属性更适合需要基于其他属性计算得出的场景,而响应式引用更适合需要跟踪其变化并在更改时触发更新的变量。
评论(0)