Vue 3 计算属性(Computed Properties)知识点详解与案例代码
在 Vue 3 中,计算属性(Computed Properties) 是用于基于响应式数据派生新数据的一种方式。计算属性具有以下特点:
- 缓存性:只有在依赖的响应式数据发生变化时,计算属性才会重新计算,否则会返回缓存的结果。
- 可读性:计算属性用于获取数据,而不是修改数据。
- 响应性:计算属性会自动追踪其依赖的响应式数据,并在依赖变化时自动更新。
一、计算属性的语法知识点
1. 基本语法
在 Vue 3 中,计算属性通常在 setup
函数中使用 computed
函数来定义。
javascript
import { ref, computed } from 'vue';
export default {
setup() {
const count = ref(0);
const doubleCount = computed(() => count.value * 2);
return {
count,
doubleCount
};
}
};
2. 使用 computed
函数
computed
函数接受一个 getter 函数 作为参数,并返回一个 只读的响应式引用(Readonly Ref)。
javascript
const double = computed(() => count.value * 2);
3. 可写的计算属性
默认情况下,计算属性是只读的。如果需要可写的计算属性,可以传递一个包含 get
和 set
方法的对象。
javascript
const firstName = ref('John');
const lastName = ref('Doe');
const fullName = computed({
get: () => `${firstName.value} ${lastName.value}`,
set: (value) => {
const parts = value.split(' ');
firstName.value = parts[0];
lastName.value = parts[1];
}
});
4. 依赖追踪
计算属性会自动追踪其内部使用的响应式数据,并在这些数据变化时重新计算。
javascript
const firstName = ref('John');
const lastName = ref('Doe');
const fullName = computed(() => `${firstName.value} ${lastName.value}`);
当 firstName
或 lastName
变化时,fullName
会自动更新。
5. 懒计算
计算属性只有在首次访问时才会计算,并且只有在依赖变化时才会重新计算。这使得计算属性在需要复杂计算时非常高效。
二、案例代码
以下是一个完整的 Vue 3 单文件组件(Single File Component, SFC)示例,展示了计算属性的使用,包括基本计算属性、可写的计算属性以及依赖追踪。
vue
<template>
<div>
<h1>Vue 3 计算属性示例</h1>
<!-- 基本计算属性 -->
<div>
<p>当前计数: {{ count }}</p>
<p>双倍计数: {{ doubleCount }}</p>
<button @click="increment">增加计数</button>
</div>
<!-- 可写的计算属性 -->
<div>
<p>全名: {{ fullName }}</p>
<input v-model="fullName" placeholder="输入全名" />
<p>名字: {{ firstName }}</p>
<p>姓氏: {{ lastName }}</p>
</div>
<!-- 依赖追踪示例 -->
<div>
<p>名字: {{ firstName }}</p>
<p>姓氏: {{ lastName }}</p>
<p>全名: {{ fullName }}</p>
<input v-model="firstName" placeholder="输入名字" />
<input v-model="lastName" placeholder="输入姓氏" />
</div>
</div>
</template>
<script>
import { ref, computed } from 'vue';
export default {
name: 'ComputedPropertiesExample',
setup() {
// 基本计算属性
const count = ref(0);
const doubleCount = computed(() => count.value * 2);
const increment = () => {
count.value++;
};
// 可写的计算属性
const firstName = ref('John');
const lastName = ref('Doe');
const fullName = computed({
get: () => `${firstName.value} ${lastName.value}`,
set: (value) => {
const parts = value.split(' ');
if (parts.length >= 2) {
firstName.value = parts[0];
lastName.value = parts[1];
} else {
firstName.value = value;
lastName.value = '';
}
}
});
return {
count,
doubleCount,
increment,
firstName,
lastName,
fullName
};
}
};
</script>
<style scoped>
h1 {
color: #42b983;
}
div {
margin-bottom: 20px;
}
button {
padding: 5px 10px;
margin-top: 5px;
}
input {
padding: 5px;
margin-top: 5px;
}
</style>
代码详解
-
导入
ref
和computed
javascriptimport { ref, computed } from 'vue';
ref
用于创建响应式数据。computed
用于创建计算属性。
-
基本计算属性
javascriptconst count = ref(0); const doubleCount = computed(() => count.value * 2);
count
是一个响应式的数据。doubleCount
是一个计算属性,其值始终是count
的两倍。
-
增加计数的函数
javascriptconst increment = () => { count.value++; };
increment
函数用于增加count
的值。
-
可写的计算属性
javascriptconst fullName = computed({ get: () => `${firstName.value} ${lastName.value}`, set: (value) => { const parts = value.split(' '); if (parts.length >= 2) { firstName.value = parts[0]; lastName.value = parts[1]; } else { firstName.value = value; lastName.value = ''; } } });
fullName
是一个可写的计算属性。- 当
fullName
被设置时,会自动更新firstName
和lastName
。 - 当
firstName
或lastName
变化时,fullName
也会自动更新。
-
模板部分
html<template> <div> <!-- 基本计算属性 --> <div> <p>当前计数: {{ count }}</p> <p>双倍计数: {{ doubleCount }}</p> <button @click="increment">增加计数</button> </div> <!-- 可写的计算属性 --> <div> <p>全名: {{ fullName }}</p> <input v-model="fullName" placeholder="输入全名" /> <p>名字: {{ firstName }}</p> <p>姓氏: {{ lastName }}</p> </div> <!-- 依赖追踪示例 --> <div> <p>名字: {{ firstName }}</p> <p>姓氏: {{ lastName }}</p> <p>全名: {{ fullName }}</p> <input v-model="firstName" placeholder="输入名字" /> <input v-model="lastName" placeholder="输入姓氏" /> </div> </div> </template>
- 基本计算属性:展示当前计数和双倍计数,并提供按钮增加计数。
- 可写的计算属性 :通过
v-model
绑定fullName
,输入全名会自动更新firstName
和lastName
。 - 依赖追踪示例 :展示
firstName
和lastName
,并通过输入框修改它们,fullName
会自动更新。
-
样式部分
css<style scoped> h1 { color: #42b983; } div { margin-bottom: 20px; } button { padding: 5px 10px; margin-top: 5px; } input { padding: 5px; margin-top: 5px; } </style>
- 使用
scoped
属性确保样式仅作用于当前组件。 - 设置了一些基本的样式。
- 使用
三、运行效果
-
基本计算属性
- 页面加载时,
count
为0
,doubleCount
为0
。 - 点击"增加计数"按钮,
count
增加,doubleCount
自动更新为count
的两倍。
- 页面加载时,
-
可写的计算属性
- 输入框中输入新的全名,例如
Jane Smith
,firstName
会更新为Jane
,lastName
会更新为Smith
。 - 修改
firstName
或lastName
,fullName
会自动更新。
- 输入框中输入新的全名,例如
-
依赖追踪示例
- 修改
firstName
或lastName
,fullName
会自动更新。 - 修改
fullName
,firstName
和lastName
会根据输入自动调整。
- 修改
四、案例代码
vue
<template>
<div class="computed-demo">
<h2>Vue3 计算属性示例</h2>
<!-- 基础用法展示 -->
<div class="basic-example">
<h3>1. 基础只读计算属性</h3>
<p>姓: <input v-model="firstName" /></p>
<p>名: <input v-model="lastName" /></p>
<p>全名: {{ fullName }}</p>
<p>全名长度: {{ fullNameLength }}</p>
</div>
<!-- 可写计算属性展示 -->
<div class="writable-example">
<h3>2. 可写计算属性</h3>
<p>输入全名: <input v-model="fullNameWritable" /></p>
<p>拆分结果: {{ firstName }} {{ lastName }}</p>
</div>
<!-- 计算属性与方法对比 -->
<div class="comparison-example">
<h3>3. 计算属性与方法对比</h3>
<p>计算属性 (缓存): {{ reversedMessage }} (访问次数: {{ computedAccessCount }})</p>
<p>方法 (无缓存): {{ reversedMessageMethod() }} (调用次数: {{ methodCallCount }})</p>
<button @click="incrementCount">点击增加计数</button>
<p>当前计数: {{ count }}</p>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
// 1. 基础示例数据
const firstName = ref('张');
const lastName = ref('三');
// 基础只读计算属性:计算全名
const fullName = computed(() => {
// 当firstName或lastName变化时,会重新计算
return `${firstName.value} ${lastName.value}`;
});
// 计算属性可以依赖其他计算属性
const fullNameLength = computed(() => {
// 依赖fullName计算属性
return fullName.value.length;
});
// 2. 可写计算属性示例
const fullNameWritable = computed({
// getter:获取值时调用
get() {
return `${firstName.value} ${lastName.value}`;
},
// setter:设置值时调用
set(newValue) {
// 将输入的全名拆分为姓和名
const [first, last] = newValue.split(' ');
firstName.value = first || '';
lastName.value = last || '';
}
});
// 3. 计算属性与方法对比示例
const count = ref(0);
const message = ref('Hello Vue3');
const computedAccessCount = ref(0);
const methodCallCount = ref(0);
// 计算属性版本:反转消息
const reversedMessage = computed(() => {
computedAccessCount.value++;
return message.value.split('').reverse().join('');
});
// 方法版本:反转消息
function reversedMessageMethod() {
methodCallCount.value++;
return message.value.split('').reverse().join('');
}
// 增加计数的方法
function incrementCount() {
count.value++;
}
</script>
<style scoped>
.computed-demo {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
div > div {
margin-bottom: 30px;
padding: 15px;
border: 1px solid #e0e0e0;
border-radius: 8px;
}
input {
padding: 6px 10px;
margin-left: 10px;
border: 1px solid #ccc;
border-radius: 4px;
}
button {
padding: 8px 16px;
background-color: #42b983;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
margin-top: 10px;
}
button:hover {
background-color: #359e75;
}
</style>
4.1.代码解析
- 基础只读计算属性
fullName
依赖firstName
和lastName
两个响应式数据- 当输入框中的值变化时,
fullName
会自动更新 fullNameLength
依赖fullName
这个计算属性,形成计算属性链
- 可写计算属性
fullNameWritable
同时定义了get
和set
方法- 当读取时,会调用
get
方法拼接全名 - 当修改输入框的值时,会调用
set
方法拆分全名到firstName
和lastName
- 计算属性与方法对比
- 点击按钮只会改变
count
的值,不会影响message
- 计算属性
reversedMessage
因为依赖没有变化,不会重新计算,访问次数不变 - 方法
reversedMessageMethod
每次访问都会重新执行,调用次数会增加
- 点击按钮只会改变
五、总结
通过上述知识点和案例代码,可以看出 Vue 3 的计算属性在处理基于响应式数据的派生数据时非常强大且高效。计算属性不仅简化了代码逻辑,还提高了应用的性能和可维护性。在实际开发中,合理使用计算属性可以大大提升开发效率和代码质量。