从 v-model 到 defineModel:Vue3 正在悄悄改变开发习惯

一、组件化与双向绑定的演变背景

1. 早期前端:手写 DOM 与状态管理痛点

在纯 JavaScript 时代,我们尝尝直接操作 DOM、管理全局变量。随着应用复杂度提升,出现了以下问题:

  • 状态混乱:UI 状态(表单值、控件可见性)散落在各个回调里,难以维护。
  • 模块化隔离不足:不同 UI 模块互相干扰,数据污染严重。
  • 手动同步:每次数据改变,都要手动 querySelector → 更新属性 → 补齐事件监听器,十分臃肿。
2. MVVM 思想与双向绑定萌芽

为了解决手工同步的痛点,AngularJS(1.x)提出了 MVVM 架构,引入双向数据绑定,模板中写一个 ng-model,改变模型(Model)或视图(View)都能自动同步。这大大提升了开发效率,但也带来性能风险——脏检查(digest cycle)在大型应用中很难调优。

Vue 1.0 受到启发,保留双向绑定优势的同时,用基于 Object.defineProperty 的响应式系统来替代脏检查,性能与体验兼得。

二、Vue 2.x 中的 v-model

1. 前言:为什么需要 v-model 呢?

在传统的网页开发中,我们经常要手动将表单输入与 JavaScript 数据做同步:

  1. 监听输入框的 input 或 change 事件;
  2. 在回调中 setState 或直接赋值;
  3. 然后在渲染函数中把数据写回到 DOM。

这种手工绑定不仅代码冗长,而且容易出错,尤其是在多表单、复杂交互场景下,维护成本极高。

Vue 2.x 引入了 MVVM(Model–View–ViewModel)的理念,通过 数据响应式 + 模板指令,让模板到数据、数据到模板的同步都只需一句话:


Vue 会在内部搞定:

  • 初始化时把 foo 的值渲染到输入框;
  • 用户输入时自动更新 foo;
  • foo 变化时又反过来更新输入框。

从而极大地简化了表单开发,提升了开发效率。

2. 基本用法

举个

输入的是:{{ message }}

new Vue({
  el: '#app',
  data: {
    message: ''
  }
});
  • 渲染阶段:Vue 把 data.message 的值赋给 的 value 属性。
  • 模版绑定:Vue 编译器把 v-model 转为 :value="message" + @input="message = $event.target.value"。
  • 交互阶段:用户输入触发 input 事件,执行赋值,内部触发 数据响应式,重新渲染视图。
2. 在不同表单控件中的应用