Vue.js双向绑定实现原理详解

发布时间 - 2026-01-10 22:00:50    点击率:

Vue.js最核心的功能有两个,一是响应式的数据绑定系统,二是组件系统。本文仅探究几乎所有Vue的开篇介绍都会提到的hello world双向绑定是怎样实现的。先讲涉及的知识点,再参考源码,用尽可能少的代码实现那个hello world开篇示例。

参考文章:https://www./article/100819.htm

一、访问器属性

访问器属性是对象中的一种特殊属性,它不能直接在对象中设置,而必须通过defineProperty()方法单独定义。

var obj = { };

// 为obj定义一个名为hello的访问器属性

Object.defineProperty(obj, "hello", {

get: function () {return sth},

set: function (val) {/* do sth */}

})

obj.hello // 可以像普通属性一样读取访问器属性

访问器属性的"值"比较特殊,读取或设置访问器属性的值,实际上是调用其内部特性:get和set函数。

obj.hello // 读取属性,就是调用get函数并返回get函数的返回值

obj.hello = "abc" // 为属性赋值,就是调用set函数,赋值其实是传参

get和set方法内部的this都指向obj,这意味着get和set函数可以操作对象内部的值。另外,访问器属性的会"覆盖"同名的普通属性,因为访问器属性会被优先访问,与其同名的普通属性则会被忽略(也就是所谓的被"劫持"了)。

二、极简双向绑定的实现

此例实现的效果是:随文本框输入文字的变化,span中会同步显示相同的文字内容;在js或控制台显式的修改obj.name的值,视图会相应更新。这样就实现了model =>view以及view => model的双向绑定,并且是响应式的。

以上就是Vue实现双向绑定的基本原理。

三、分解任务

上述示例仅仅是为了说明原理。我们最终要实现的是:

首先将该任务分成几个子任务:

   1、输入框以及文本节点与data中的数据绑定

   2、输入框内容变化时,data中的数据同步变化。即view => model的变化。

   3、data中的数据变化时,文本节点的内容同步变化。即model => view的变化。

要实现任务一,需要对DOM进行编译,这里有一个知识点:DocumentFragment。

四、DocumentFragment

DocumentFragment(文档片段)可以看作节点容器,它可以包含多个子节点,当我们将它插入到DOM中时,只有它的子节点会插入目标节点,所以把它看作一组节点的容器。使用DocumentFragment处理节点,速度和性能远远优于直接操作DOM。Vue进行编译时,就是将挂载目标的所有子节点劫持(真的是劫持)到DocumentFragment中,经过一番处理后,再将DocumentFragment整体返回插入挂载目标。

五、数据初始化绑定

以上代码实现了任务一,我们可以看到,hello world已经呈现在输入框和文本节点中。

六、响应式的数据绑定

再来看任务二的实现思路:当我们在输入框输入数据的时候,首先触发input事件(或者keyup、change事件),在相应的事件处理程序中,我们获取输入框的value并赋值给vm实例的text属性。我们会利用defineProperty将data中的text劫持为vm的访问器属性,因此给vm.text赋值,就会触发set方法。在set方法中主要做两件事,第一是更新属性的值,第二留到任务三再说。

任务二也就完成了,text属性值会与输入框的内容同步变化:

七、订阅/发布模式(subscribe&publish)

text属性变化了,set方法触发了,但是文本节点的内容没有变化。如何让同样绑定到text的文本节点也同步变化呢?这里又有一个知识点:订阅发布模式。

订阅发布模式(又称观察者模式)定义了一种一对多的关系,让多个观察者同时监听某一个主题对象,这个主题对象的状态发生改变时就会通知所有观察者对象。

发布者发出通知 => 主题对象收到通知并推送给订阅者 => 订阅者执行相应操作

之前提到的,当set方法触发后做的第二件事就是作为发布者发出通知:“我是属性text,我变了”。文本节点则是作为订阅者,在收到消息后执行相应的更新操作。

八、双向绑定的实现

回顾一下,每当new一个Vue,主要做了两件事:第一个是监听数据:observe(data),第二个是编译HTML:nodeToFragement(id)。

在监听数据的过程中,会为data中的每一个属性生成一个主题对象dep。

在编译HTML的过程中,会为每个与数据绑定相关的节点生成一个订阅者watcher,watcher会将自己添加到相应属性的dep中。

我们已经实现:修改输入框内容 => 在事件回调函数中修改属性值 => 触发属性的set方法。

接下来我们要实现的是:发出通知dep.notify() => 触发订阅者的update方法 => 更新视图。

这里的关键逻辑是:如何将watcher添加到关联属性的dep中。

在编译HTML过程中,为每个与data关联的节点生成一个Watcher。Watcher函数中发生了什么呢?

首先,将自己赋给了一个全局变量Dep.target;

其次,执行了update方法,进而执行了get方法,get的方法读取了vm的访问器属性,从而触发了访问器属性的get方法,get方法中将该watcher添加到了对应访问器属性的dep中;

再次,获取属性的值,然后更新视图。

最后,将Dep.target设为空。因为它是全局变量,也是watcher与dep关联的唯一桥梁,任何时刻都必须保证Dep.target只有一个值。

至此,hello world双向绑定就基本实现了。文本内容会随输入框内容同步变化,在控制器中修改vm.text的值,会同步反映到文本内容中(但输入框还没有绑定,读者可以自己试试)。

完整代码:https://github.com/bison1994/two-way-data-binding

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


# Vue.js  # 双向绑定  # 深入理解vue.js双向绑定的实现原理  # 解析Vue2.0双向绑定实现原理  # 如何理解Vue的作用域插槽的实现原理  # Vue底层实现原理总结  # 浅谈vue中数据双向绑定的实现原理  # Vue中的基础过渡动画及实现原理解析  # Vue分页器实现原理详解  # Vue 2.0的数据依赖实现原理代码简析  # 浅析vue中的MVVM实现原理  # 浅析vue-router实现原理及两种模式  # Vue简单实现原理详解  # 绑定  # 输入框  # 的是  # 件事  # 过程中  # 多个  # 实现了  # 当我们  # 会为  # 将该  # 象中  # 我是  # 全局变量  # 就会  # 还没有  # 第一个  # 也就  # 一是  # 则是  # 又有 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Win11摄像头无法使用怎么办_Win11相机隐私权限开启教程【详解】  详解一款开源免费的.NET文档操作组件DocX(.NET组件介绍之一)  如何快速搭建高效WAP手机网站?  阿里云高弹*务器配置方案|支持分布式架构与多节点部署  关于BootStrap modal 在IOS9中不能弹出的解决方法(IOS 9 bootstrap modal ios 9 noticework)  Laravel Eloquent:优雅地将关联模型字段扁平化到主模型中  如何在云指建站中生成FTP站点?  Mybatis 中的insertOrUpdate操作  Laravel怎么做缓存_Laravel Cache系统提升应用速度的策略与技巧  公司门户网站制作流程,华为官网怎么做?  利用JavaScript实现拖拽改变元素大小  Laravel中的withCount方法怎么高效统计关联模型数量  百度浏览器ai对话怎么关 百度浏览器ai聊天窗口隐藏  Laravel如何配置任务调度?(Cron Job示例)  三星、SK海力士获美批准:可向中国出口芯片制造设备  Laravel怎么发送邮件_Laravel Mail类SMTP配置教程  Edge浏览器怎么启用睡眠标签页_节省电脑内存占用优化技巧  PythonWeb开发入门教程_Flask快速构建Web应用  PHP 500报错的快速解决方法  香港服务器WordPress建站指南:SEO优化与高效部署策略  Laravel中间件起什么作用_Laravel Middleware请求生命周期与自定义详解  标准网站视频模板制作软件,现在有哪个网站的视频编辑素材最齐全的,背景音乐、音效等?  如何在IIS管理器中快速创建并配置网站?  iOS发送验证码倒计时应用  laravel服务容器和依赖注入怎么理解_laravel服务容器与依赖注入解析  php485函数参数是什么意思_php485各参数详细说明【介绍】  Laravel怎么创建自己的包(Package)_Laravel扩展包开发入门到发布  Laravel如何使用Vite进行前端资源打包?(配置示例)  如何快速生成高效建站系统源代码?  如何用y主机助手快速搭建网站?  香港服务器网站测试全流程:性能评估、SEO加载与移动适配优化  Laravel如何使用Contracts(契约)进行编程_Laravel契约接口与依赖反转  Win10如何卸载预装Edge扩展_Win10卸载Edge扩展教程【方法】  HTML透明颜色代码怎么让下拉菜单透明_下拉菜单透明背景指南【技巧】  如何快速重置建站主机并恢复默认配置?  Java Adapter 适配器模式(类适配器,对象适配器)优缺点对比  韩国服务器如何优化跨境访问实现高效连接?  香港服务器网站推广:SEO优化与外贸独立站搭建策略  香港服务器如何优化才能显著提升网站加载速度?  如何在Ubuntu系统下快速搭建WordPress个人网站?  Laravel Eloquent模型如何创建_Laravel ORM基础之Model创建与使用教程  简单实现jsp分页  武汉网站设计制作公司,武汉有哪些比较大的同城网站或论坛,就是里面都是武汉人的?  javascript基本数据类型及类型检测常用方法小结  如何在IIS中新建站点并解决端口绑定冲突?  Laravel如何处理表单验证?(Requests代码示例)  Laravel怎么进行数据库事务处理_Laravel DB Facade事务操作确保数据一致性  夸克浏览器网页跳转延迟怎么办 夸克浏览器跳转优化  如何在橙子建站中快速调整背景颜色?  网站制作公司哪里好做,成都网站制作公司哪家做得比较好,更正规?