Vue3 学习笔记(七)Vue3 语法-计算属性 computed详解

时间:2024-10-27 07:10:16

#1024程序员节|征文#

在这里插入图片描述


1、计算属性 computed


在 Vue.js 中,计算属性(computed properties)是一种特殊的响应式属性,它们根据依赖的响应式数据自动更新。计算属性非常适合用于当你需要根据现有数据派生出一些状态时。


(1)、基本用法

计算属性是通过在组件的 computed 选项中定义的。它们使用一个函数来计算值,这个函数的返回值就是计算属性的值。这个函数会接收组件实例作为上下文(即 this),并可以访问组件的响应式数据。

import { computed, ref } from 'vue';

export default {
  setup() {
    const count = ref(0);

    // 定义一个计算属性
    const doubledCount = computed(() => count.value * 2);

    return {
      count,
      doubledCount
    };
  }
};

在上面的示例中,doubledCount 是一个计算属性,它依赖于 count。每当 count 的值变化时,doubledCount 会自动更新。


(2)、缓存性

计算属性具有缓存性,这意味着只有当依赖的响应式数据变化时,计算属性才会重新计算。这可以提高性能,特别是当计算属性的计算成本较高时。

import { computed, ref } from 'vue';

export default {
  setup() {
    const count = ref(0);

    // 定义一个计算属性
    const expensiveComputed = computed(() => {
      console.log('Computing expensive value...');
      return count.value * 2;
    });

    return {
      count,
      expensiveComputed
    };
  }
};

在这个例子中,每次 count 更新时,控制台都会打印 “Computing expensive value…”,但由于计算属性的缓存性,这个日志只会在 count 实际变化时出现。


(3)、不是所有场景都适合计算属性

虽然计算属性很强大,但它们并不适用于所有场景。如果某个值的计算不依赖于响应式数据,或者需要在每次访问时都进行计算(例如,随机数生成),则不应该使用计算属性。


(4)、计算属性 vs 方法

计算属性与方法(methods)不同。方法在每次调用时都会执行函数,而计算属性则具有缓存性,只有当依赖的数据变化时才会重新计算。因此,如果你需要在每次访问时都执行计算,应该使用方法而不是计算属性。

import { ref } from 'vue';

export default {
  setup() {
    const now = ref(Date.now());

    // 使用方法而不是计算属性
    const timeString = () => now.value.toLocaleTimeString();

    return {
      now,
      timeString
    };
  }
};

2、计算属性应用场景


计算属性(computed properties)在 Vue.js 中适用于多种场景,尤其是当你需要根据组件中现有的响应式数据来声明派生数据时。以下是一些计算属性的应用场景示例:


(1)、根据多个数据属性计算新的数据

假设你有一个组件,它维护了用户的购物车信息,包括商品的原价和折扣后的价格。你可能需要计算商品的最终价格。

<template>
  <div>
    <p>原价: {{ product.originalPrice }}</p>
    <p>折扣价: {{ product.discountedPrice }}</p>
    <p>最终价格: {{ finalPrice }}</p>
  </div>
</template>

<script>
import { computed, reactive } from 'vue';

export default {
  setup() {
    const product = reactive({
      originalPrice: 100,
      discountedPrice: 80
    });

    const finalPrice = computed(() => product.originalPrice * product.discountedPrice / 100);

    return {
      product,
      finalPrice
    };
  }
};
</script>

(2)、根据用户输入动态计算结果

在表单中,你可能需要根据用户输入的数据动态计算一些结果,如总价、折扣、税费等。

<template>
  <div>
    <input v-model="quantity" type="number" placeholder="数量">
    <input v-model="pricePerItem" type="number" placeholder="单价">
    <p>总价: {{ totalPrice }}</p>
  </div>
</template>

<script>
import { computed, ref } from 'vue';

export default {
  setup() {
    const quantity = ref(1);
    const pricePerItem = ref(0);

    const totalPrice = computed(() => quantity.value * pricePerItem.value);

    return {
      quantity,
      pricePerItem,
      totalPrice
    };
  }
};
</script>

(3)、根据数组内容计算新的数组

如果你有一个商品列表,你可能需要根据这个列表计算出一些新的列表,比如筛选后的列表或排序后的列表。

<template>
  <div>
    <ul>
      <li v-for="item in filteredProducts" :key="item.id">
        {{ item.name }} - {{ item.price }}
      </li>
    </ul>
  </div>
</template>

<script>
import { computed, ref } from 'vue';

export default {
  setup() {
    const products = ref([
      { id: 1, name: 'Product A', price: 100 },
      { id: 2, name: 'Product B', price: 200 },
      // more products
    ]);

    const filteredProducts = computed(() =>
      products.value.filter(product => product.price > 100)
    );

    return {
      filteredProducts
    };
  }
};
</script>

(4)、根据对象数据计算新的值

如果你有一个对象,包含用户的基本信息,你可能需要根据这些信息计算出一些新的值,比如年龄、全名等。

<template>
  <div>
    <p>用户信息:</p>
    <p>名字: {{ user.name }}</p>
    <p>姓氏: {{ user.surname }}</p>
    <p>全名: {{ fullName }}</p>
  </div>
</template>

<script>
import { computed, reactive } from 'vue';

export default {
  setup() {
    const user = reactive({
      name: 'John',
      surname: 'Doe',
      birthday: '1990-01-01'
    });

    const fullName = computed(() => `${user.name} ${user.surname}`);

    return {
      user,
      fullName
    };
  }
};
</script>

(5)、性能优化

计算属性可以用于性能优化,避免在模板或方法中重复执行相同的计算逻辑。

<template>
  <div>
    <p>列表长度: {{ listLength }}</p>
  </div>
</template>

<script>
import { computed, ref } from 'vue';

export default {
  setup() {
    const items = ref([/* ... */]);

    const listLength = computed(() => items.value.length);

    return {
      listLength
    };
  }
};
</script>

在这些示例中,计算属性允许你将复杂的逻辑放在 JavaScript 中处理,同时保持模板的简洁和声明性。这使得你的组件更容易维护和理解。


3、计算属性最佳实践


以下是一些使用计算属性的最佳实践:

(1)、 保持简洁

计算属性应该只包含必要的逻辑,用于根据响应式数据派生新的值。避免在计算属性中执行副作用操作,如 API 调用或更改其他响应式状态。


(2)、 避免复杂逻辑

如果计算属性的逻辑变得过于复杂,考虑将其拆分为多个更小的计算属性或方法。


(3)、 使用缓存

利用计算属性的缓存特性,避免不必要的计算。只有当依赖的数据变化时,计算属性才会重新计算。这意味着在模板或其他地方多次使用计算属性时,它只会计算一次。


(4)、 避免直接修改计算属性

计算属性是只读的,不应该直接修改。如果你需要修改计算属性的值,应该修改它的依赖数据。


(5)、选择合适的名称

给计算属性取一个清晰和描述性的名称,这样其他开发者可以很容易地理解这个计算属性的用途。


(6)、避免在计算属性中进行异步操作

计算属性应该基于同步操作,因为它们是响应式系统的同步部分。异步操作应该在方法或生命周期钩子中处理。


(7)、使用计算属性而不是观察者

如果你发现自己需要在多个地方执行相同的计算逻辑,考虑使用计算属性而不是使用 watch 或 `watchEffec


(8)、避免在模板中使用复杂表达式

对于模板中需要的复杂表达式,应该使用计算属性而不是在模板中直接编写复杂表达式。


(9)、组合使用计算属性和侦听器

在某些情况下,你可能需要在计算属性变化时执行额外的逻辑。这时,可以结合使用计算属性和 watch 侦听器。


(10)、考虑使用 watchEffect

如果你需要在多个响应式数据变化时执行副作用,考虑使用 watchEffect 而不是计算属性。


示例:计算属性和 watch 组合使用

<template>
  <div>{{ fullName }}</div>
</template>

<script>
import { computed, watch, ref } from 'vue';

export default {
  setup() {
    const firstName = ref('');
    const lastName = ref('');

    const fullName = computed(() => `${firstName.value} ${lastName.value}`);

    watch(fullName, (newName, oldName) => {
      console.log(`Name changed from ${oldName} to ${newName}`);
      // 执行一些副作用,比如 API 调用
    });

    return {
      fullName,
      firstName,
      lastName
    };
  }
};
</script>

在上述示例中,fullName 是一个计算属性,它依赖于 firstNamelastName。我们使用 watch 来侦听 fullName 的变化,并在变化时执行副作用。