概述
计算属性,顾名思义,根据属性计算出一个新值,该值被称为计算属性。
- 如根据商品数量,计算数量总和
- 再如根据商品数量和单价计算总价
vue3中如何创建计算属性
- 创建fish组件
- 引入computed
- 组件数据为鱼类和鱼类价格(鱼类单价为用户输入)
- 计算所有鱼类总价
首先看input标签,input标签有两个属性,一是value,一是v-model,两者区别。
- value是单向数据,只能由数据到页面
- v-model是双向数据,即可数据到页面;也可页面输入,数据跟着响应变化
value如下几种用法
ini
<input value="鲫鱼"/>
<input :value="fish[1].name">
<input v-bind:value="fish[1].name">
value将数据写死。:value是 v-bind:value简写方式,实现数据到页面。
v-model双向数据绑定
v-model数v-model.value缩写。注意是点,不是冒号,与v-bind:value区别。它可实现页面和数据双向绑定
xml
<template>
<h2>详解input:
<input value="鲤鱼">
<input v-bind:value="fish[0].name">
<input :value="fish[0].name">
</h2>
<h2>鱼类:{{ fish[0].name }} <br>价格:<input v-model.value.number="fish[0].price"/></h2>
<h2>鱼类:{{ fish[1].name }} <br>价格:<input v-model.number="fish[1].price"/></h2>
<h2>总价1:{{ fish[0].price+fish[1].price}}</h2>
<h2>总价2:{{ totalPrice }}</h2>
</template>
<script setup>
import { reactive,computed } from 'vue'
let fish = reactive([
{ name: '鲫鱼', price: 10},
{ name: '鲤鱼', price: 30 }
]);
let totalPrice= computed(() => {
return fish[0].price + fish[1].price;
})
</script>
运行查看效果
价格通过两种方式计算,一是在模版中计算,二是通过计算属性totalPrice得到
css
<h2>总价1:{{ fish[0].price+fish[1].price}}</h2>
<h2>总价2:{{ totalPrice }}</h2>
为何在模版中可以计算,还要引入computed计算属性。假如数据一千条鱼,总价超过1000优惠5%,模版中应该是:
css
<h2>总价2:{{
fish.reduce((a, item) => a + item.price, 0)<1000?fish.reduce((a, item) => a + item.price, 0):(fish.reduce((a, item) => a + item.price, 0))*0.95
}}</h2>
此时在模版中编写业务逻辑,就变得复杂臃肿。违背一个原则,官方文档说明,尽量在模版中使用简单的表达式。
计算属性computed的特点
- 计算属性依赖的数据变化,它才会重新计算
- 多次引用计算属性,它只计算一次,相比与方法是要多次计算的 代码如下,创建一个方法用于计算鱼类总价,在价格超过1000时优惠5%
xml
<template>
<h2>鱼类:{{ fish[0].name }} <br>价格:<input v-model.value.number="fish[0].price"/></h2>
<h2>鱼类:{{ fish[1].name }} <br>价格:<input v-model.number="fish[1].price"/></h2>
<h2>总价1:{{ totalPrice }}</h2>
<h2>总价2:{{ totalPrice }}</h2>
<h2>总价3:{{ calcTotalPrice() }}</h2>
<h2>总价4:{{ calcTotalPrice() }}</h2>
</template>
<script setup>
import { reactive,computed } from 'vue'
let fish = reactive([
{ name: '鲫鱼', price: 10},
{ name: '鲤鱼', price: 30 }
]);
function calcTotalPrice() {
console.log('calcTotalPrice');
const t = fish.reduce((a, item) => a + item.price, 0);
return t< 1000 ? t : t * 0.95;
}
let totalPrice = computed(() => {
console.log('computed');
const t = fish.reduce((a, item) => a + item.price, 0);
return t< 1000 ? t : t * 0.95;
})
</script>
事例中,计算属性和方法各引用两次。页面打开时,控制台输出一次computed,两次calcTotalPrice。每改变一次单价,computed计算一次,方法计算两次。
- 数据变化,computed只调用一次
- 数据变化,方法多次调用
计算属性能不能修改
通过上诉定义的计算属性totalPrice不可修改,当你通过如下代码修改totalPrice的值时
ini
totalPrice.value = 100;
它会提示一条警告:16 [Vue warn] Write operation failed: computed value is readonly 通过控制台打印,看看计算属性到底是什么,如图:
计算属性使用ComputedRefImpl 结构定义,赋值时用 totalPrice.value = 100;。
修改计算属性的值
计算属性的值是可以修改的,但需要通过特殊的方法定义
xml
<template>
<h2>鱼类:{{ fish[0].name }} <br>价格:<input v-model.value.number="fish[0].price"/></h2>
<h2>鱼类:{{ fish[1].name }} <br>价格:<input v-model.number="fish[1].price"/></h2>
<h2>总价1:{{ totalPrice }}</h2>
<button @click="calcTotalPrice">修改计算属性的值</button>
</template>
<script setup>
import { reactive,computed } from 'vue'
let fish = reactive([
{ name: '鲫鱼', price: 10},
{ name: '鲤鱼', price: 30 }
]);
function calcTotalPrice() {
totalPrice.value = 100;
}
let totalPrice = computed({
get() {
const t = fish.reduce((a, item) => a + item.price, 0);
return t< 1000 ? t : t * 0.95;
},
set(val) {
console.log(val)
console.log(totalPrice.value)
}
})
</script>
如图当我们点击修改计算属性的值时,它只是调用set函数,totalPrice的值并又有改变。 原因在于,totalPrice是根据鱼的价格计算而来,只有改变鱼的价格,才能够改变totalPrice值。修改set函数的内容即可:
ini
set(val) {
console.log(val)
console.log(totalPrice.value)
fish[0].price = 40;
fish[1].price = 60;
}