首先我们还是老规矩,先介绍他是什么
computed(计算属性)
computed是一种基于响应式数据依赖的属性(计算属性),它可以根据其他响应式数据进行计算,并返回一个新的值,计算属性的值会根据其依赖的数据自动更新,当依赖的数据发生变化时,计算属性会重新计算并返回新的值
我们先来看computed,我现在要你用代码实现一个根据两个input框,分别输入姓和名,然后再将拼接为姓名,你会怎么写.
<template>
<div>
姓:<input type="text" v-model="firstname"><br>
名:<input type="text" v-model="lastname"><br>
姓名: <span>{{ firstname }}{{ lastname }} </span>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
let firstname = ref('zhang')
let lastname = ref('san')
</script>
<style lang="scss" scoped></style>
我相信应该大部分人是这样写的,很nice,也实现了功能
这个时候我们如果再加上一个要求姓的首字母需要大写,我相信大家依旧没问题,通过切片,和toUppercase(),
<span>{{ firstname.slice(0, 1).toUpperCase() + firstname.slice(1) }}{{ lastname }} </span>
也实现了但是这会导致模板里的代码有了复杂的表达式,Vue3提倡大家在<template>标签中书写尽可能简单的代码,这个时候我们就需要使用计算属性了.
<template>
<div>
姓:<input type="text" v-model="firstname"><br>
名:<input type="text" v-model="lastname"><br>
<!-- 姓名: <span>{{ firstname }}{{ lastname }} </span> -->
姓名: <span>{{ fullname }}</span>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
let firstname = ref('zhang')
let lastname = ref('san')
let fullname = computed(() => {
return firstname.value.slice(0, 1).toUpperCase() + firstname.value.slice(1) + lastname.value
})
console.log(fullname);
</script>
<style lang="scss" scoped></style>
可以看到computed他是依赖firstname和lastname这两个响应式数据进行计算的,定义了一个fullname去获得这个计算属性,打印fullname,来看一看他是不是
ComputedRefImpl是实现计算属性(computed)的内部类。
他只有当其依赖的响应式数据发生变化时,才会触发更新
<template>
<div>
姓:<input type="text" v-model="firstname"><br>
名:<input type="text" v-model="lastname"><br>
<!-- 姓名: <span>{{ firstname }}{{ lastname }} </span> -->
姓名: <span>{{ fullname }}</span>
姓名: <span>{{ fullname }}</span>
姓名: <span>{{ fullname }}</span>
姓名: <span>{{ fullname }}</span>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
let firstname = ref('zhang')
let lastname = ref('san')
let fullname = computed(() => {
return firstname.value.slice(0, 1).toUpperCase() + firstname.value.slice(1) + lastname.value
console.log(1)
})
console.log(fullname);
</script>
<style lang="scss" scoped></style>
虽然调用了四遍计算属性 fullname,但是只输出了一个1,说明计算属性是很聪明的,他是有缓存的.
这样定义的 fullname虽然是计算属性但是它是只读的,即不可以修改。
大家估计这个时候就会有疑问了,我在输入框输入字符进去,明明fullname框里的值在改动啊,怎么就不可以修改了,而说fullname是 “只读” 的,是指不能直接给fullname赋值来修改它的值。例如,不能像这样fullname = 'new value'去修改它。因为它的值是由计算得出的,依赖于其他响应式数据,而不是可以直接被赋值修改的独立变量。所以,虽然在界面上看起来fullname的值在变化,但这是由于其依赖项的变化导致重新计算的结果,而不是直接对fullname进行了修改!!!
我们需要换一个写法去定义计算属性,这样定义的是可以修改的,来看下面的一段代码.
<template>
<div>
姓:<input type="text" v-model="firstname"><br>
名:<input type="text" v-model="lastname"><br>
姓名: <span>{{ fullname }}</span>
<button @click="changefullname">把名字改为lisi</button>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
let firstname = ref('zhang');
let lastname = ref('san');
const fullname = computed({
get: () => {
return firstname.value.slice(0, 1).toUpperCase() + firstname.value.slice(1) + lastname.value;
},
set: (val) => {
let [str1, str2] = val.split('-');
firstname.value = str1;
lastname.value = str2;
}
});
function changefullname() {
fullname.value = 'li-si'
}
</script>
<style lang="scss" scoped></style>
我们需要理解set() 和 get()
一、get方法的作用
-
计算并返回值:
get方法用于定义如何计算出计算属性的值。在这个例子中,它根据firstname和lastname的值,将firstname的首字母大写后与剩余部分以及lastname拼接在一起,返回一个新的字符串作为fullname的值。 -
响应式依赖:当在
get方法中访问了响应式数据(这里是firstname.value和lastname.value)时,Vue 会自动建立起计算属性对这些响应式数据的依赖关系。当这些依赖的数据发生变化时,Vue 会自动重新调用get方法来更新计算属性的值,确保计算属性始终反映最新的状态。
二、set方法的作用
-
反向设置依赖数据:
set方法允许通过给计算属性赋值来反向影响其依赖的响应式数据。在这个例子中,当给fullname赋值时,set方法会被调用。它接收一个参数val,这个参数是赋给计算属性的值。然后,通过对这个值进行分割,分别更新firstname和lastname的值。 -
维护响应式关系:通过这种方式,可以在一定程度上实现双向数据绑定的效果。当外部修改了计算属性的值时,能够通过
set方法正确地更新依赖的响应式数据,从而保持整个响应式系统的一致性。
总的来说,get和set方法共同定义了计算属性的行为,使得计算属性既可以根据依赖数据自动计算值,又可以通过赋值来反向影响依赖数据,为 Vue 的响应式系统提供了更强大的功能和灵活性。
这样定义的computed既可以直接修改fullname的值,也可以通过fullname的值去反向影响依赖数据! 是不是很妙.
🐟End
Computed(计算属性)能高效、简洁且可维护地处理派生数据。例如,多处需显示根据用户输入的价格和数量得出的总价时,用计算属性可将计算总价逻辑集中一处定义,提升代码可维护性。它基于依赖的响应式数据缓存,依赖数据不变时,多次访问直接返回缓存值,不重复计算以提高性能;依赖数据变化时,自动更新以确保同步,从而提升性能。可以很好的帮助开发者!