Vue双向数据绑定实现原理
1 访问器属性是对象中的一种特殊属性,它不能直接在对象中设置,而必须通过 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.hello 的值,视图会相应更新。这样就实现了 model => view 以及 view => model 的双向绑定。
以上就是 Vue 实现双向绑定的基本原理。
三、分解任务
上述示例仅仅是为了说明原理。我们最终要实现的是:
首先将该任务分成几个子任务:
1、输入框以及文本节点与 data 中的数据绑定(
每次new一个vue,都调用了new selfVue函数,把el,data,methods,...作为一个对象当成参数传给selfVue函数,用Object.keys遍历data对象的每个属性,对其所有属性都进行监听,
让他们成为访问器属性,都有getter和setter方法,同时会调用observe(this.data),就是为了初始化一个监听器,监听data中的数据,然后new Compile(options.el,this)就是
初始化一个解析器,遍历其所有节点,判断是元素节点还是文本节点,如果是文本节点就直接编译,第一步初始化视图数据,第二步初始化一个订阅者(new Watcher()),并给订阅者绑定更新函数,然后订阅者就会把自己自动
添加到订阅器中,如果是元素节点,就要区分具体是什么指令,解析这些指令,如果是事件指令就给他绑定事件,如果是v-model类似的指令,就给他绑定input事件,并且完成挂载,更新视图,同时初始化
一个订阅者,并绑定更新函数
)
2、输入框内容变化时,data 中的数据同步变化。即 view => model 的变化。
(
修改输入框内容,在事件回调中修改属性值,(通过self.vm[exp]=newValue,触发selfVue中的setter去修改的)
,)
3、data 中的数据变化时,文本节点的内容同步变化。即 model => view 的变化。
(
属性变了,就触发监听器里的setter,就会触发订阅器的dep.notify(),这个函数会遍历所有
订阅者去更新,订阅者收到通知,就会执行绑定的更新函数
,)
要实现任务一,需要对 DOM 进行编译,这里有一个知识点:DocumentFragment。
八、双向绑定的实现
回顾一下,每当 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 只有一个值。
https://juejin.im/entry/59116fa6a0bb9f0058aaaa4c
https://github.com/DDFE/DDFE-blog/issues/7
Vue双向数据绑定实现原理的更多相关文章
- 详解 vue 双向数据绑定的原理,并实现一组双向数据绑定
1:vue 双向数据绑定的原理: Object.defineProperty是ES5新增的一个API,其作用是给对象的属性增加更多的控制Object.defineProperty(obj, prop, ...
- vue双向数据绑定的原理-object.defineProperty() 用法
有关双向数据绑定的原理 关于数据双向绑定的理解:利用了 Object.defineProperty() 这个方法重新给对象定义了新属性,在操作新属性分别为为获取属性值(调用get方法)和设置属性值(调 ...
- angular和vue双向数据绑定
angular和vue双向数据绑定的原理(重点是vue的双向绑定) 我在整理javascript高级程序设计的笔记的时候看到面向对象设计那章,讲到对象属性分为数据属性和访问器属性,我们平时用的js对象 ...
- vue实现双向数据绑定的原理
vue实现双向数据绑定的原理就是利用了 Object.defineProperty() 这个方法重新定义了对象获取属性值(get)和设置属性值(set)的操作来实现的. 在MDN上对该方法的说明是:O ...
- vue的双向数据绑定实现原理
在目前的前端面试中,vue的双向数据绑定已经成为了一个非常容易考到的点,即使不能当场写出来,至少也要能说出原理.本篇文章中我将会仿照vue写一个双向数据绑定的实例,名字就叫myVue吧.结合注释,希望 ...
- vue的双向数据绑定实现原理(简单)
如果有人问你,学vue学到了什么,那双向数据绑定,是必然要说的. 我们都知道,在vue中,使用数据双向绑定我们都知道是v-modle实现的. 实现原理是通过Object.defineProperty的 ...
- Vue双向数据绑定原理分析(转)
add by zhj: 目前组里使用的是前端技术是jQuery + Bootstrap,后端使用的Django,Flask等,模板是在后端渲染的.前后端没有分离,这种做法有几个缺点 1. 模板一般是由 ...
- vue双向绑定的原理及实现双向绑定MVVM源码分析
vue双向绑定的原理及实现双向绑定MVVM源码分析 双向数据绑定的原理是:可以将对象的属性绑定到UI,具体的说,我们有一个对象,该对象有一个name属性,当我们给这个对象name属性赋新值的时候,新值 ...
- vue 双向数据绑定的实现学习(二)- 监听器的实现
废话:上一篇https://www.cnblogs.com/adouwt/p/9928278.html 提到了vue实现的基本实现原理:Object.defineProperty() -数据劫持 和 ...
随机推荐
- python在Linux中安装虚拟环境,区别python2和python3,分别安装模块
安装虚拟环境的时候遇到的问题,解决的过程很闹心,在这里简单直接的分享出来,就是为了解决问题. 安装虚拟环境(须在联网状态下) $ sudo pip install virtualenv $ sudo ...
- [NOIP2016day2T1] 組合數問題(problem)
题目描述 组合数C(n,m)表示的是从n个物品中选出m个物品的方案数.举个例子,从(1,2,3) 三个物品中选择两个物品可以有(1,2),(1,3),(2,3)这三种选择方法.根据组合数的定 义,我们 ...
- [bzoj2648/2716]SJY摆棋子_KD-Tree
SJY摆旗子 bzoj-2648 题目大意:平面上有n个黑子.有m个操作,可以下一颗白子,查询与曼哈顿距离下最近黑子之间的曼哈顿距离,或者下一颗黑子. 注释:$1\le n,m\le 5\cdot 1 ...
- [转]C#综合揭秘——深入分析委托与事件
引言 本篇文章将为你介绍一下 Delegate 的使用方式,逐渐揭开 C# 当中事件(Event)的由来,它能使处理委托类型的过程变得更加简单.还将为您解释委托的协变与逆变,以及如何使用 Delega ...
- Jemeter命令执行
http://mp.weixin.qq.com/s?__biz=MzAxOTg2NDUyOA==&mid=2657555034&idx=1&sn=9e6a3fbd5eed859 ...
- 本地项目上传虚拟机的gitlab
前提:在虚拟机安装了gitlab服务,并且本机可以访问到虚拟机的gitlab 自己本机项目上传到gitlab 1.先在gitlab上建立项目 拷贝项目地址: http://192.168.1.105/ ...
- hdu4430之枚举+二分
Yukari's Birthday Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Other ...
- C#获取本机Sql Serverserver名
private void Form2_Load(object sender, EventArgs e) { listBox1.Items.Clear(); SQLDMO.Application SQL ...
- Framebuffer子系统【转】
本文转载自:http://blog.csdn.net/av_geek/article/details/40897115 本文将介绍Framebuffer子系统 目标平台:TQ2440 CPU:s3c2 ...
- 【POJ 2230】 Watchcow
[题目链接] http://poj.org/problem?id=2230 [算法] 欧拉回路 [代码] #include <algorithm> #include <bitset& ...