前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库Vue defineModel
VuVue组件与模板

Vue 3.4 的 defineModel 宏相比手写 modelValue 加 update 事件简化了什么?

defineModel 把重复的 prop、事件和桥接 computed 交给编译器生成,但状态所有权协议没有改变。

前端进阶之旅 · 一题精讲更新于 2026.09.06
Vue#组件与模板
先看核心答案读代码示例
理解线索

宏隐藏的是样板代码

  1. 读取模型 ref等价于读取对应 prop
  2. 写入模型 ref等价于发出 update 事件
  3. 编译结果公开契约仍可被父级 v-model 使用

宏改善作者体验,不会把父子状态变成共享可变变量,也不会自动完成异步校验。

核心回答

先记住这个答案

defineModel 是 Vue 3.4+ 的 <script setup> 编译期宏。无参数调用会声明 modelValue prop 和 update:modelValue 事件,并返回一个可读写 ref;读取 ref 得到父级值,写入 ref 会发出更新事件。传入字符串可创建 v-model:title 等命名通道,类型参数、required、default、get/set 和修饰符也能一起声明。它不需要导入,也不能在普通运行时函数中动态调用。若子组件给模型设置 default 而父级绑定值起初是 undefined,双方可能暂时不同步,应优先由父级初始化或明确处理缺省值。

  • 宏生成 prop 与 update 事件
  • 返回 ref 可直接读写
  • Vue 3.4+ 编译器与默认值边界要明确

编译器生成重复的桥接层

手写组件通常要声明 modelValue、update:modelValue,再用 computed get/set 或事件处理器把两者连起来。defineModel 把这三部分压缩成一个 ref,模板可以直接对该 ref 使用原生输入 v-model。

因为它是编译期宏,源码必须位于 <script setup> 顶层,构建工具需要兼容版本。不能 import defineModel 后在条件分支里调用,也不能仅升级运行时而保留旧的 SFC 编译器。组件库应在发布配置中声明版本要求。

默认通道与命名通道可以并列

下例创建默认字符串模型和名为 count 的数字模型。title.value 赋值会通知父级默认通道,count.value 赋值会发出 update:count。required 让类型排除 undefined,但父级运行时仍需真的传值。

修饰符可通过解构模型返回值取得,并用 get/set 选项规范化。转换应保持同步、确定,涉及网络和失败的流程仍用显式 action 或事件。

用 defineModel 声明两个模型通道TypeScript
// <script setup lang="ts">
const title = defineModel<string>({ required: true })
const count = defineModel<number>('count', { default: 0 })

function rename() {
  title.value = title.value.trim()
}

function increment() {
  count.value += 1
}

父级使用 v-model 和 v-model:count 连接两个通道。该代码需要 Vue 3.4+ 的 SFC 编译器;它不是可直接交给浏览器执行的普通 TypeScript 模块。

默认值可能制造两个初始真相

父级 ref 为 undefined、子模型配置 default: 1 时,子组件先看到 1,而父级仍是 undefined,直到子级发出更新才可能同步。这与普通 prop 默认值一致,却更容易因模型 ref 可写而被误认为已经双向同步。

最稳妥的方式是让父级初始化受控状态,或在接口设计中允许 undefined 并显式归一化。SSR 页面还要确保服务端与客户端使用同一初值,否则首次文本和 hydration 可能不一致。

回答前,多想一步

容易答错的地方

在普通 setup 文件里导入并调用 defineModel
它只在 <script setup> 编译上下文中识别,不是运行时组合式函数。可复用逻辑应接收 ref 或回调,模型宏留在组件边界。
把可写 ref 当成直接修改父变量
写入会发出更新事件,父级仍可能拒绝、转换或延迟写回。需要乐观草稿时要明确暂存状态,不能假设赋值已经被父级接受。
试着用自己的话回答

面试官还会怎么问?

怎样拿到自定义修饰符?

可以写 const [model, modifiers] = defineModel(),再通过 set 选项读取 modifiers 并返回转换后的值。支持哪些键应写进组件文档与类型。

defineModel 能完全替代 defineProps 和 defineEmits 吗?

只能替代模型相关的 prop 与更新事件。其他输入和业务事件仍应分别声明,避免把所有交互都伪装成双向状态。

组件库为什么还要理解底层事件名?

调试、类型发布、旧版本兼容和测试都需要知道实际公开契约。宏生成的仍是对应 prop 与 update 事件,不是新的运行时通信通道。

从一道题,走向一组知识

把知识连起来

组件与模板

Vue 中子组件如何支持 v-model,默认的 prop 名和事件名是什么?

底层 modelValue 与 update 事件是理解宏行为的基础。

组件与模板

Vue 3 中一个组件如何实现多个 v-model 绑定?

字符串参数会创建命名模型通道。

组件与模板

如何在 Vue 自定义组件的 v-model 上支持自定义修饰符?

宏可以取得修饰符并用 get/set 处理值。

参考资料

  • Vue:defineModel 宏
  • Vue:组件 v-model 底层机制

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 编译器生成重复的桥接层
  3. 默认通道与命名通道可以并列
  4. 默认值可能制造两个初始真相
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑