Vue3中的v-model、computed、watch

目录

一、v-model

二、v-bind

三、computed(计算属性)​

原理深度解析​​

​​经典使用场景​​

四、watch(侦听器)​​

​​核心作用​:​

​​原理深度解析​​

​​核心配置选项​​

​​经典使用场景​​

五、watchEffect(即时副作用)​​

​​核心作用​:​

​​原理深度解析​​

​​独特优势​​

​​经典使用场景​​


一、v-model

核心作用:​ ​ v-model 的主要功能是在​​表单输入元素​ ​或​​自定义 Vue 组件​ ​上创建​​双向数据绑定​​。它同时负责数据的读取(将 Vue 数据绑定到视图)和数据的写入(将用户输入同步回 Vue 数据)。

在原生表单元素上的实现原理:

html 复制代码
<!-- HTML 模板 -->
<input v-model="username">

等效于以下写法:

html 复制代码
<input 
  :value="username"
  @input="username = $event.target.value"
>

在自定义组件上的实现原理:

html 复制代码
<custom-input v-model="username">

等效于以下写法:

html 复制代码
<custom-input
  :model-value="username"
  @update:model-value="username = $event"
>

组件内部实现:

javascript 复制代码
// 自定义组件内部
props: ['modelValue'],
emits: ['update:modelValue'],

methods: {
  handleInput(e) {
    this.$emit('update:modelValue', e.target.value)
  }
}

二、v-bind

​​核心作用:​ ​ v-bind 的核心功能是​​动态地将 Vue 实例(组件)中的数据绑定到 HTML 元素的属性(Attribute)或组件的属性(Prop)上​​。

:model ​​是 Vue 的动态属性绑定语法​​,由两部分组成:

  • 冒号' : '它是' v-bind:'的缩写
  • 属性名 model:任意自定义的属性名
  • 完整形式:v-bind:model="dataObj"

:model 不是一个内置指令或特殊属性,而是一种常见的命名约定,表示"传递整个模型对象"。

:model 的本质

  • 是 v-bind:model 的简写形式
  • 仅用于单向数据传递(父 → 子)
  • 无内置行为,是纯属性绑定
  • 依赖开发者明确定义props接收

v-model 和 :model 的区别

​​特性​​ ​​v-model​​ ​​:model​​
​​类型​​ Vue指令 动态属性绑定
​​功能​​ 双向数据绑定 单向数据绑定
​​实现​​ 属性+事件绑定 仅属性绑定
​​用途​​ 表单输入组件 传递任意对象
​​示例​​ <input v-model="val"> <child :model="dataObj">
​​组件实现​​ 需要emit更新事件 仅接收props

适用场景选择

场景 推荐
​​表单输入绑定​​ v-model
​​复杂数据传递​​ :model
​​组件通信​​ 组合使用 :model + 自定义事件
​​多个数据绑定​​ 多个 v-model(如 v-model:user)

三、computed(计算属性)​

**核心作用​:**​

创建​​响应式的派生数据​​,基于其他响应式数据自动计算结果并缓存

javascript 复制代码
import { computed } from 'vue'

// 基本用法
const fullName = computed(() => `${firstName.value} ${lastName.value}`)

// 可写计算属性
const writableComputed = computed({
  get() { return modelValue.value },
  set(newVal) { modelValue.value = newVal }
})

let visibleDialog = computed({
  get() {
    return props.visible;
  },
  set() {
    closeDialog();
  },
});
原理深度解析​​
  1. ​惰性求值​:仅当依赖项变化时才重新计算(首次访问时也会计算)
  2. ​依赖追踪​:运行时自动追踪getter函数内访问的响应式数据
  3. ​缓存机制​:依赖项未变化时直接返回缓存结果(多次访问不重复计算)
  4. ​响应式传播​:计算属性本身就是响应式ref,改变会自动触发依赖更新
  5. ​更新时机​:在Vue的响应式更新周期中同步执行
​​经典使用场景​​
  • 格式化/组合数据(如 ${firstName} ${lastName})
  • 过滤/转换数据(如 todos.filter(t => !t.done))
  • 复杂数学运算(如购物车总价计算)
  • 从props派生组件内部状态(需可写计算属性)
  • 替代模板中复杂表达式(提升可读性)

computed 的自动依赖追踪原理:

​​computed 会监听内部所有依赖的响应式变量值变化,自动触发重新计算并缓存结果。​

javascript 复制代码
const tipsVisible1 = computed(() => repulseForm.backToModifyType == 1);

详细过程

​​依赖收集阶段​​:

  • 当首次访问 computed 属性时,Vue 会执行计算函数
  • 计算函数内部访问的每一个响应式变量(如 repulseForm.backToModifyType) 都会通过"发布-订阅"机制将这个计算函数标记为自身的一个依赖

​​响应更新阶段​​:

  • 当这些被依赖的响应式变量值改变时:
    • 所有依赖它的计算函数会自动触发重新计算
    • 结果会被缓存,如果依赖没有变化则直接返回缓存值

​​缓存机制​​:

  • 当多次访问 chooseNodeVisible1 时:
  • 只有当 repulseForm.backToModifyType 改变时才会重新计算
  • 否则直接返回上次计算结果

示例:

javascript 复制代码
let visibleDialog = computed({
  get() {
    return props.visible;
  },
  set() {
    closeDialog();
  },
});

​​触发 getter​​:

  • 首次访问时
  • 依赖项 (props.visible) 变化后再次访问时
  • 每次在模板中渲染时

​​触发 setter​​:

  • 任何赋值操作 (visibleDialog.value = ...)
  • 即使赋予的值与当前值相同
  • 通过 v-model 绑定时被调用

四、watch(侦听器)​​

​**​核心作用​:**​

​​显式侦听特定数据源​ ​,在变化时执行副作用(异步请求、DOM操作等)​

javascript 复制代码
import { watch } from 'vue'

// 监听单一源
watch(count, (newVal, oldVal) => {
  console.log(`计数变化: ${oldVal} → ${newVal}`)
})

// 监听多个源
watch([firstName, lastName], ([newFirst, newLast]) => {
  // 处理变化...
})

// 深度监听对象
watch(
  () => ({ ...user }), 
  (newUser) => { /* 处理 */ },
  { deep: true, immediate: true }
)
​​原理深度解析​​
  1. ​精确依赖​:必须显式指定监听的数据源(ref、reactive、getter函数)
  2. ​变化检测​ :默认浅层比较(对象需手动开启deep:true)
  3. ​回调机制​:提供新旧值对比能力
  4. ​异步执行​ :默认在组件​更新后​ 执行(通过flush选项可调整时机)
  5. ​资源回收​:自动绑定组件生命周期(卸载时自动取消监听)
​​核心配置选项​​
选项 作用 典型场景
deep 深度监听嵌套对象变化 表单对象监听
immediate 立即执行回调 初始数据加载
flush 控制回调执行时机 DOM操作时使用'post'
​​经典使用场景​​
  • 异步操作、副作用操作
  • API数据获取(搜索词变化时发起请求)​
  • 路由参数监听($route.params.id变化时加载数据)
  • 表单验证(字段变化时触发验证)
  • 操作历史记录(状态变化时记录操作)

深度监听:

javascript 复制代码
watch(
  // 源获取函数:只监听user.profile对象
  () => user.profile,
  
  // 变化回调
  (newProfile) => {
    console.log("用户资料更新:", newProfile);
    // 执行相关操作
  },
  
  // 配置选项
  { deep: true } // 启用深度监听
);
javascript 复制代码
// 以下操作都会触发监听:
user.profile.name = "张三";     // 修改属性
user.profile.address.city = "北京"; // 修改嵌套属性
user.profile.hobbies.push("阅读");  // 修改数组内容
javascript 复制代码
// 如果需要新旧值对比,应创建副本:
watch(
  () => ({ ...user.profile }), // 创建浅拷贝
  (newProfile, oldProfile) => {
    // 现在可以比较具体变化
  },
  { deep: true }
);
javascript 复制代码
// watchEffect精确控制
watchEffect(() => {
  // 只追踪需要的具体属性
  if (needTracking) {
    const importantValue = someObj.deep.nested.value;
    // 使用importantValue...
  }
});

五、watchEffect(即时副作用)​​

​**​核心作用​:**​

​​自动追踪依赖​ ​并立即执行副作用,响应式数据变化时自动重新运行​

javascript 复制代码
import { watchEffect } from 'vue'

// 基本用法
const stop = watchEffect(() => {
  document.title = `消息(${unreadCount.value})`
})

// 清理副作用
watchEffect((onCleanup) => {
  const timer = setTimeout(() => {...}, 1000)
  onCleanup(() => clearTimeout(timer))
})

// 控制执行时机
watchEffect(() => {...}, { flush: 'post' })
​​原理深度解析​​
  1. ​自动依赖收集​:运行时自动追踪函数内访问的所有响应式数据
  2. ​立即执行​ :首次调用时同步执行(与watch的immediate模式不同)
  3. ​智能清理​ :通过onCleanup注册清理函数(下次执行前调用)
  4. ​动态依赖​:每次执行重新收集依赖(条件分支变化时自动调整)
  5. ​执行控制​ :默认在组件​更新前​ 执行(DOM操作用flush: 'post')
​​独特优势​​
  • 避免手动维护依赖列表
  • 处理动态依赖(条件分支中的响应式数据)
  • 更符合命令式编程思维
  • 简化初始化逻辑(自动执行)
​​经典使用场景​​
  • 实时更新DOM(如标题、滚动位置)
  • 自动请求取消(onCleanup中取消请求)
  • 监听鼠标/键盘事件(自动取消注册)
  • 表单自动保存(输入变化后定时保存)
  • 日志记录(自动跟踪变化数据)

​​三者的对比决策表​​

特性 computed watch watchEffect
​​返回类型​​ 响应式ref 无 无
​​执行时机​​ 需要时计算 变化后回调 立即+变化时
​​依赖声明​​ 自动 显式声明 自动
​​新旧值​​ 无 提供 无
​​缓存机制​​ ✅ ❌ ❌
​​异步支持​​ ❌(纯函数) ✅ ✅
​​清理机制​​ ❌ ❌ ✅(onCleanup)
​​典型用途​​ 派生数据 响应变化 执行副作用

**如何选择?**​

  1. 需要​推导新数据​ 吗? → computed
  2. 需要​获取变化前后值​ 吗? → watch
  3. 操作​包含异步/副作用​ 吗?
    • 依赖明确 → watch
    • 依赖动态 → watchEffect
  4. 需要​自动执行初始化​ ? → watchEffect
  5. 涉及​资源清理​ ? → watchEffect(onCleanup)

​​最佳实践​ ​:优先使用computed派生数据,用watchEffect处理副作用,只在需要精确控制时使用watch

总结:

computed

  • 自动追踪依赖关系
  • 懒计算(在访问时执行)
  • 结果缓存(依赖未变则返回缓存)
  • 适用于模板绑定、值派生、多依赖计算

watch

  • 显示声明监听目标
  • 即时响应数据变化
  • 支持异步操作
  • 适用于数据联动、异步操作、复杂副作用处理

相关推荐
kyriewen1 小时前
Skills 榜前 10 我全装了:只有 3 个能直接用
前端·javascript·程序员
IT_陈寒1 小时前
当Java的hashCode遇上Lombok,我的缓存被全清了
前端·人工智能·后端
工控丫丫2 小时前
帆软看板中经常使用的公式函数及经常搭的组合
前端·javascript·数据库
jerrywus2 小时前
我用 GPT-6.1-sol 做了台会讲解的 3D 售货机:60 罐饮料,一口没喝上
前端·agent·claude
孟陬4 小时前
Foobar 技术周刊#159:当看不懂代码时,如何高效排障调试。脏页陷阱:一条只读查询,写入数 TB 数据。推测解码:大模型加速利器
前端·人工智能·后端
Zhao-Jichao4 小时前
AI Prompting for Everyone 课程笔记 - P17 图像生成 Imaging Generation
前端
Highcharts.js4 小时前
智能数据分析组件Orbit 正式发布与快速上手体验教程
前端·人工智能·信息可视化·数据分析系统·highcharts·orbit·智能可视化
螺丝钉tina5 小时前
[Playwright ][16]Playwright + TypeScript API 自动化测试实战:API测试
前端·javascript·typescript
小天源6 小时前
智叟云集系统 · 架构与职责分层
服务器·前端·数据库
Highcharts.js7 小时前
React 中原生支持使用 JSX 组件配置自定义表格 Highcharts Grid
前端·javascript·react.js·前端框架·jsx·highcharts·自定义表格