手撸一个Vue(看不懂可以举报)
手撸一个Vue(看不懂可以举报)作为编程讲师我深知很多同学对Vue的响应式原理充满好奇却又望而却步。今天我们就从零开始一步一步“手撸”一个简化版的Vue。如果你看完还看不懂欢迎举报我但请相信跟着代码走一遍你会发现自己比想象中更强大。## 什么是Vue的核心Vue的核心是“响应式数据”和“模板渲染”。简单来说就是当数据变化时视图自动更新。要实现这个我们需要解决三个问题1.如何监听数据变化—— 使用Object.definePropertyVue2或ProxyVue3。2.如何知道哪些视图依赖了哪些数据—— 通过“依赖收集”。3.数据变化时如何更新视图—— 触发更新函数。我们先从最简单的版本开始一步步完善。## 第一步监听数据变化基础版我们先用Object.defineProperty实现数据监听。这个API可以拦截对象的读取和赋值操作。javascript// 监听对象的所有属性function observe(obj) { if (typeof obj ! object || obj null) return; Object.keys(obj).forEach(key { let value obj[key]; // 递归监听嵌套对象 observe(value); Object.defineProperty(obj, key, { get() { console.log(读取属性 ${key}: ${value}); return value; }, set(newVal) { if (newVal ! value) { console.log(更新属性 ${key}: ${value} - ${newVal}); value newVal; // 如果新值是对象继续监听 observe(newVal); } } }); });}// 测试const data { name: 小明, age: 18 };observe(data);data.name 小红; // 输出更新属性 name: 小明 - 小红console.log(data.name); // 输出读取属性 name: 小红运行这段代码你会发现每次读取或修改属性时控制台都会打印信息。这就是Vue2响应式的底层基础。## 第二步依赖收集中级版光监听数据还不够我们需要知道“谁”依赖了这个数据。比如模板中用到了{{ name }}那么当name变化时就要重新渲染这个模板片段。这里我们引入一个“依赖管理器”——DepDependency每个属性都有一个Dep实例。当读取属性时把当前的“观察者”Watcher加入依赖列表当属性变化时通知所有观察者更新。javascript// 依赖管理器class Dep { constructor() { this.subs []; // 存储所有观察者 } // 添加观察者 addSub(watcher) { this.subs.push(watcher); } // 通知所有观察者 notify() { this.subs.forEach(watcher watcher.update()); }}// 观察者代表一个需要更新的视图片段class Watcher { constructor(obj, key, callback) { this.obj obj; this.key key; this.callback callback; // 在读取属性前先把当前Watcher存入全局 Dep.target this; // 触发getter把当前Watcher加入依赖 obj[key]; Dep.target null; } update() { console.log(属性 ${this.key} 变化了执行更新); this.callback(); }}// 改造observe函数为每个属性创建Depfunction observe(obj) { if (typeof obj ! object || obj null) return; Object.keys(obj).forEach(key { let value obj[key]; const dep new Dep(); // 每个属性有自己的Dep observe(value); Object.defineProperty(obj, key, { get() { // 如果当前有Watcher在读取就加入依赖 if (Dep.target) { dep.addSub(Dep.target); } return value; }, set(newVal) { if (newVal ! value) { value newVal; observe(newVal); dep.notify(); // 通知所有观察者 } } }); });}// 测试const data { name: 小明 };observe(data);// 创建一个观察者依赖data.namenew Watcher(data, name, () { console.log(视图更新显示新名字);});data.name 小红; // 输出属性 name 变化了执行更新// 输出视图更新显示新名字现在当data.name变化时对应的观察者就会执行更新函数。这就是Vue依赖收集的雏形。## 第三步实现微型Vue高级版现在我们把上面的概念组合成一个微型Vue类。它接收一个选项对象包含data和el挂载元素并解析模板中的{{}}插值。javascriptclass MiniVue { constructor(options) { this.$options options; this.$data options.data; // 1. 监听数据 observe(this.$data); // 2. 编译模板 this.$el document.querySelector(options.el); this.compile(this.$el); } // 编译模板替换{{}}为数据 compile(node) { const childNodes node.childNodes; childNodes.forEach(child { if (child.nodeType 3) { // 文本节点 const oldText child.textContent; const reg /\{\{(.*?)\}\}/g; // 匹配{{key}} if (reg.test(oldText)) { // 提取变量名 const key RegExp.$1.trim(); // 创建观察者数据变化时更新文本 new Watcher(this.$data, key, () { child.textContent oldText.replace(reg, this.$data[key]); }); // 初始化渲染 child.textContent oldText.replace(reg, this.$data[key]); } } else if (child.nodeType 1) { // 元素节点递归编译 this.compile(child); } }); }}// 使用微型Vueconst app new MiniVue({ el: #app, data: { message: Hello Vue!, count: 0 }});// 3秒后修改数据视图自动更新setTimeout(() { app.$data.message Hello MiniVue!;}, 3000);对应的HTMLhtmldiv idapp p{{ message }}/p p{{ count }}/p/div运行这段代码你会看到页面显示“Hello Vue!”3秒后自动变成“Hello MiniVue!”。恭喜你你已经手撸了一个微型Vue## 第四步进阶思考我们的微型Vue还有哪些不足1.不支持数组Object.defineProperty无法监听数组索引变化Vue2通过重写数组方法解决。2.不支持v-model等指令真正的Vue有复杂的指令系统。3.性能优化模板编译可以生成渲染函数而不是直接操作DOM。4.计算属性和侦听器需要额外的依赖管理。Vue3使用Proxy替代Object.defineProperty可以原生监听数组和动态新增属性性能也更好。## 总结通过本文我们一步步实现了-数据监听使用Object.defineProperty拦截get/set。-依赖收集Dep管理Watcher在get时收集依赖set时通知更新。-模板编译解析{{}}插值创建Watcher实现数据驱动视图。虽然只有100多行代码但已经包含了Vue响应式系统的核心思想。现在你应该明白Vue并不是什么黑魔法而是一套优雅的设计模式。如果你跟着代码写了一遍还是不懂欢迎举报我——但请带上你的代码我们一起debug编程路上动手永远比空想更重要。下次面试官问你Vue原理你可以自信地说“我手撸过一个。”

相关新闻

基于springboot的客户管理系统订单管理档案管理的设计与实现(源码+LW+部署讲解)

基于springboot的客户管理系统订单管理档案管理的设计与实现(源码+LW+部署讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/10/10 15:14:25 阅读更多 →
如何3分钟解锁Windows家庭版远程桌面:终极完整解决方案

如何3分钟解锁Windows家庭版远程桌面:终极完整解决方案

如何3分钟解锁Windows家庭版远程桌面:终极完整解决方案 【免费下载链接】SuperRDP Super RDPWrap 项目地址: https://gitcode.com/gh_mirrors/su/SuperRDP 还在为Windows家庭版无法使用远程桌面功能而烦恼吗?SuperRDP正是解决这一痛点的完美方案。…

2026/10/10 15:18:06 阅读更多 →
零成本搭建数字人直播间:从技术原理到实战部署

零成本搭建数字人直播间:从技术原理到实战部署

如果你正在寻找"零成本搭建数字人直播间"的解决方案,那么这篇文章可能会颠覆你的认知。市面上很多教程宣称"免费",但实际操作中往往隐藏着各种限制和隐性成本。本文将带你深入了解数字人直播的技术本质,并提供真正可落地…

2026/10/3 14:33:04 阅读更多 →

最新新闻

supabase-postgres-best-practices - schema-partitioning

supabase-postgres-best-practices - schema-partitioning

title: Partition Large Tables for Better Performance impact: MEDIUM-HIGH impactDescription: 5-20x faster queries and maintenance on large tables tags: partitioning, large-tables, time-series, performance 对大表进行分区以获得更好的性能 分区将大表拆分为更小…

2026/10/12 4:36:45 阅读更多 →
litellm实战:统一大模型API网关,解决多厂商接入痛点

litellm实战:统一大模型API网关,解决多厂商接入痛点

如果你同时对接过三家以上大模型厂商的 API,大概率体会过那种“每家都长得差不多,每家都不一样”的憋屈。请求体里的字段名不同、认证方式不同、返回结构不同,甚至同一个模型名在不同平台下的效果也天差地别。以前我的处理方式是在业务代码里…

2026/10/12 4:36:45 阅读更多 →
Apache Beam ZetaSQL 方言详解:语法、数据类型、函数与 BigQuery 兼容实践

Apache Beam ZetaSQL 方言详解:语法、数据类型、函数与 BigQuery 兼容实践

批处理流处理大数据 【免费下载链接】beam Apache Beam is a unified programming model for Batch and Streaming data processing. 项目地址: https://gitcode.com/gh_mirrors/beam15/beam 点击查看 免费下载 本文以 Apache Beam 官方文档中的 Beam ZetaSQL 总览…

2026/10/12 4:36:45 阅读更多 →
supabase-postgres-best-practices - security-rls-performance

supabase-postgres-best-practices - security-rls-performance

title: Optimize RLS Policies for Performance impact: HIGH impactDescription: 5-10x faster RLS queries with proper patterns tags: rls, performance, security, optimization 优化 RLS 策略以提升性能 编写不当的 RLS 策略会导致严重的性能问题。应策略性地使用子查询…

2026/10/12 4:36:45 阅读更多 →
aiogram 实时位置编辑指南:editMessageLiveLocation 方法全方位解析

aiogram 实时位置编辑指南:editMessageLiveLocation 方法全方位解析

后端即时通讯API设计 【免费下载链接】aiogram aiogram is a modern and fully asynchronous framework for Telegram Bot API written in Python using asyncio 项目地址: https://gitcode.com/gh_mirrors/ai/aiogram 点击查看 免费下载 实时位置(Live…

2026/10/12 4:36:45 阅读更多 →
AnyPS5跨平台游戏串流工具:从画面采集到客户端渲染的技术拆解与调优实践

AnyPS5跨平台游戏串流工具:从画面采集到客户端渲染的技术拆解与调优实践

1. 从"AnyPS5"这个名字说起:一个跨平台游戏串流工具的设计初衷第一次看到"AnyPS5"这个命名,我的直觉是:这大概率是一个围绕主机游戏远程游玩场景做的工具类项目。名字里的"Any"暗示了跨平台、跨设备的通用性诉…

2026/10/12 4:35:44 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:54 阅读更多 →