Skip to content

Vue 计算属性

Vue 计算属性

简介

在 Vue 模板中可以使用表达式进行计算,但也只能用来做简单的计算逻辑。

如果在模板中写太多逻辑,会让模板变得臃肿,难以维护。

并且,如果这段臃肿的逻辑需要在代码中多次使用,那么无论从开发角度还是代码维护角度,都是不好的。

此时,就可以使用 Vue 中提供的计算属性解决此类问题。

computed() 函数

Vue 使用 computed() 函数在 setup() 函数中定义计算属性,该函数使用前需要从 Vue 中导入。

const { createApp, ref,computed } = Vue
  • computed() 方法期望接收一个 getter 函数,返回值为一个计算属性 ref
  • 和其他一般的 ref 类似,你可以通过 属性.value 访问计算结果。
  • 计算属性 ref 也会在模板中自动解包,因此在模板表达式中引用时无需添加 .value
  • 和普通的响应式变量相同,都需要在 setup() 函数中返回对象中进行暴露。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 引入 Vue -->
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <script>
        const { createApp, ref, computed } = Vue

        window.onload = function(){
            createApp({
                setup() {
                    const firstName = ref("Michael")
                    const lastName = ref("Jordan")
                    // 添加计算属性
                    const fullName = computed(()=>{
                        console.log("FullName")
                        return firstName.value + "." + lastName.value
                    })
                    return {
                        // 暴露计算属性
                        fullName
                    }
                }
            }).mount('#app');
        }
      </script>

</head>
<body>

    <!-- 添加元素,通过Vue展示数据 -->
    <div id="app">
        <div>计算属性:{{ fullName }}</div>
    </div>

</body>
</html>

计算属性缓存 vs 方法

你可能注意到如果在表达式中直接调用一个函数也会获得和计算属性相同的结果,那么为什么还要使用计算属性呢?

实际上,计算属性除了可以简化逻辑外,最大的优势是基于其响应式依赖数据的缓存。

一个计算属性仅会在其响应式依赖更新时才重新计算。这意味着只要其依赖的响应式变量不发生改变,无论访问多少次计算属性,都会立即返回之前缓存的计算结果。

而函数会在每次调用时,都会重新计算。

对上面的示例代码进行修改后,

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 引入 Vue -->
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <script>
        const { createApp, ref, computed } = Vue

        window.onload = function(){
            createApp({
                setup() {
                    const firstName = ref("Michael")
                    const lastName = ref("Jordan")
                    // 计算属性
                    const fullName = computed(()=>{
                        console.log("FullName")
                        return firstName.value + "." + lastName.value
                    })
                    // 函数
                    function getfullName(){
                        console.log("GetFullName")
                        return firstName.value + "." + lastName.value
                    }
                    // 事件响应函数
                    function changeFirstName(){
                        firstName.value += "A"
                    }
                    // 暴露数据
                    return {
                        fullName,
                        getfullName,
                        changeFirstName
                    }
                }
            }).mount('#app');
        }

      </script>

</head>
<body>

    <!-- 添加元素,通过Vue展示数据 -->
    <div id="app">

        <div>
            <div>计算属性:{{ fullName }}</div>
            <div>函数调用:{{ getfullName() }}</div>
        </div>
        <div>
            <div>计算属性:{{ fullName }}</div>
            <div>函数调用:{{ getfullName() }}</div>
        </div>
        <div>
            <div>计算属性:{{ fullName }}</div>
            <div>函数调用:{{ getfullName() }}</div>
        </div>

        <div>
            <button @click="changeFirstName">修改响应式变量值</button>
        </div>
    </div>

</body>
</html>

通过浏览器调试工具查看输出,可以看到,多次使用计算属性时,计算属性逻辑只执行了一次,而函数每次都会执行。

当响应式变量的值被修改时,计算属性只会计算一次,然后通过缓存直接引用结果,但函数依然每次都要执行。

可写计算属性

计算属性默认是只读的。当尝试修改一个计算属性时,会收到一个运行时警告。

只在某些特殊场景中可能才需要用到可写的属性,比如,对计算属性中所涉及的多个响应式变量同时更改时,就可以使用可写计算属性实现。

可以通过同时提供 gettersetter 方法来创建。

格式:

const 计算属性名 = computed({
  // getter
  get() {
    return ...
  },
  // setter
  set(newValue) {
    ...
  }
})

修改上面的示例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 引入 Vue -->
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <script>
        const { createApp, ref, computed } = Vue

        window.onload = function(){
            createApp({
                setup() {
                    const firstName = ref("Michael")
                    const lastName = ref("Jordan")
                    // 计算属性
                    const fullName = computed({
                        get(){
                            console.log("FullName")
                            return firstName.value + "." + lastName.value
                        },
                        set(newValue){
                            [firstName.value, lastName.value] = newValue.split(".")
                        }
                    })
                    // 函数
                    function getfullName(){
                        console.log("GetFullName")
                        return firstName.value + "." + lastName.value
                    }
                    // 事件响应函数
                    function changeFirstName(){
                        // 修改计算属性的值
                        fullName.value = "A.B"
                        console.log(firstName.value)
                        console.log(lastName.value)
                    }
                    // 暴露数据
                    return {
                        fullName,
                        getfullName,
                        changeFirstName
                    }
                }
            }).mount('#app');
        }

      </script>

</head>
<body>

    <!-- 添加元素,通过Vue展示数据 -->
    <div id="app">

        <div>
            <div>计算属性:{{ fullName }}</div>
            <div>函数调用:{{ getfullName() }}</div>
        </div>
        <div>
            <div>计算属性:{{ fullName }}</div>
            <div>函数调用:{{ getfullName() }}</div>
        </div>
        <div>
            <div>计算属性:{{ fullName }}</div>
            <div>函数调用:{{ getfullName() }}</div>
        </div>

        <div>
            <button @click="changeFirstName">修改响应式变量值</button>
        </div>
    </div>

</body>
</html>

总结

  • computed() 函数可以添加计算属性,提高代码效率
  • 计算属性基于响应式依赖实现
  • 可以通过添加 setter 函数为计算属性添加可写功能