vue教程-计算属性(computed) vs 侦听属性(watch)

本质

computed 计算属性

依赖缓存的派生值:基于已有数据计算出新数据,有缓存,只有依赖变量改变才重新执行函数,模板直接渲染结果。
语法:key: 函数 / {get, set}
用途:数据转换、多数据合并、复杂表达式简化。

watch 侦听器

数据变化的回调监听:监听指定变量,变量一变就执行一段逻辑(无返回值,侧重动作),无缓存,每次数据更新都会触发。
语法:key: 处理函数 / {handler, deep, immediate}
用途:异步操作、复杂业务逻辑、多步骤操作、深度监听对象/数组。

对比表

对比维度 computed(计算属性) watch(侦听器)
核心目的 得到一个计算后的值(供页面渲染) 数据变化后执行一段行为/逻辑
缓存机制 有缓存;依赖不变,多次访问只算一次 无缓存;数据一更新就执行
返回值 必须 return 结果,模板可直接插值使用 不需要 return,函数内写业务操作
使用场景 1. 模板复杂表达式简化 2. 多变量合并计算 3. 简单数据格式化 1. 异步请求(接口) 2. 复杂多步逻辑 3. 对象/数组深度监听 4. 数据变更触发DOM、定时器
写法限制 不能写异步、复杂副作用逻辑 适合写异步、定时器、赋值、请求
初始化执行 页面渲染时自动执行一次(计算初始值) 默认页面初始化不执行,需加 immediate: true
监听深度 只能监听基础依赖,对象内部属性不追踪 配置 deep: true 可深度监听对象、数组
多依赖 天然支持多个依赖变量,任意一个变化就更新 一个 watch 只能监听一个目标,多变量需写多个watch

使用场景

选择

  • 要生成新值、页面渲染用 → 优先 computed
  • 简单拼接、四则运算、字符串格式化一律用 computed
  • 数据变了要做异步、请求、定时器、复杂操作 → 用 watch
  • 监听对象内部属性、数组内容变化、初始化就要执行逻辑,用 watch 加 deep/immediate

computed 计算属性适用场景

  1. 页面展示需要组合/加工现有数据
    比如拼接姓名、总价求和、数字格式化、状态文字转换(0=禁用,1=启用)、多条件判断展示标签文本。

  2. 简化模板复杂表达式
    模板里大量三元、加减、数组过滤,提取成计算属性让页面更简洁。

  3. 同一计算结果多处复用
    页面多个地方用到同一个加工后的值,有缓存,不会重复计算,性能更好。

  4. 需要双向改写派生数据
    由多个基础字段合成一个字段,同时支持修改该字段反向拆分更新原数据(get+set)。

watch 侦听器适用场景

  1. 表单值变化实时 校验、提示错误。如:年龄、价格不能是负数,也不能超过最大值;密码复杂度不符合要求;两次密码不一致;

  2. 在数据变化时,发送 ajax请求。如:百度的输入框的提示;输入验证码,自动向服务器发请求校验是否正确;

  3. 数据变动触发副作用逻辑
    值改变开启/关闭定时器、弹窗、路由跳转、打印日志、重置表单。

  4. 监听对象、数组内部深层修改
    修改表单对象里某一个属性、数组新增删除元素后执行逻辑。

  5. 页面初始化就要执行一次监听逻辑
    进入页面立刻根据当前数据执行一遍业务,不需要等手动修改数据。

  6. 单一数据变化触发多步骤复杂流程
    一个值改动要连续执行赋值、判断、调用多个方法等一系列操作。

快速区分选用规则

  • 目的是得到一个新值给页面渲染 → computed
  • 目的是数据变了去做某一件事 → watch

易错点

  1. computed 内部不要写异步(定时器、axios),缓存机制会失效;
  2. watch 监听数组:数组push/splice等方法能触发,但直接赋值对象需要deep;
  3. 能用 computed 绝不写 watch,computed 性能更好;
  4. computed 依赖必须是响应式数据,普通全局变量不会触发更新。

总结

  • 计算属性(computed)的函数必须有返回值;侦听属性(watch)不需要

  • 计算属性(computed)能实现的功能,侦听属性(watch)都能实现,可能会啰嗦些

  • 侦听属性(watch)能实现的功能,计算属性(computed)不一定能实现,可以实现异步

侦听属性例子

侦听属性可以实现异步功能(计算属性无法实现),如:延时1秒后执行

<div id="app">
    输入出生年份:<input type="text" v-model="birthday"><br>
    年龄:<span>{{age}}</span>(表达式只写监听属性名,会自动调用 监听方法)<br>
    年龄:<span>{{age}}</span><br>
    年龄:<span>{{age}}</span><br>
    年龄:<span>{{age}}</span>(计算属性会缓存结果,如:显示4次年龄,初始化时只执行1次监听方法)
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>


<script>
    var vm = new Vue({
        el: '#app',
        data:{
            birthday:'',
            age:''
        },
        watch:{
            // 侦听 birthday 属性值变化
            birthday:function(newValue,oldValue){
                setTimeout(() => {
                    console.log("birthday值从 "+oldValue+" 改为 "+newValue)
                    this.age=new Date().getFullYear() - this.birthday.substr(0,this.birthday.indexOf("-"))
                }, 1000);
            }
        }
    })

</script>

原文出处:/show_1IX2eveZiMXw.html