-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
重温vue双向绑定原理解析 #3
Comments
四 : 有错别字 while |
订阅发布模式 与 观察者模式 不是一回事儿吧? |
另外,你最后面是不是写错了 //在此处将所有的监测器watcher添加进发布器,每一个属性都有自己的发布器
if(dep.target) dep.addSub(dep.target); dep.target 应该改为 Dep.target 吧? |
@BigKongfuPanda 是的,这两个的确不是一个模式。的这是我早期的文章犯的错误,谢谢指正。 |
噢。没事儿,很多人都把这两个模式弄混了。vue的响应式原理是标准的观察者模式。 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
本篇文章大多数知识点实在学习了这篇Vue.js双向绑定的实现原理之后避免遗忘,所以写这个温故知新,加强理解。
一、访问器属性
如果稍微看过相关文章的人都知道vue的实现是依靠Object.defineproperty()来实现的。每个对象都有自己内置的set和get方法,当每次使用set时,去改变引用该属性的地方,从而实现数据的双向绑定。简单举例
二、极简双向绑定的实现
基于这个原理,如果想实现显示文字根据输入input变化,实现一个简单版的。
上面这个实例实现的效果是:随着文本框输入文字的变化,span会同步显示相同的文字内容。同时在控制台用js改变obj.hello,视图也会更新。这样就实现了view->model,model->view的双向绑定。
三、拆解任务,实现vue的双向数据绑定
我们最终实现下面vue的效果
1.输入框的文本与文本节点的data数据绑定
2.输入框的内容发生变化时,data中的数据也发生变化,实现view->model的变化
3.data中的数据发生变化时,文本节点的内容同步发生变化,实现model->view的变化
要实现1的要求,则又涉及到了dom的编译,其中有一个DocumentFragment的知识点。
四、DocumentFragment
众所周知,vue吸收了react虚拟DOM的优点,使用DocumentFragment处理节点,其性能和速度远胜于直接操作dom。vue进行编译时,就是将所有挂载在dom上的子节点进行劫持到使用DocumentFragment处理节点,等到所有操作都执行完毕,将DocumentFragment再一模一样返回到挂载的目标上。
先实现一段劫持函数,将要操作的dom全部劫持到DocumentFragment中,然后再append会原位置。
五、数据初始化绑定
当已经获取到所有的dom元素之后,则需要对数据进行初始化绑定,这里简单涉及到了模板的编译。
通过以上代码先实现了第一个要求,文本框和文本节点已经出现了hello woeld了
六、响应式的数据绑定
接下来我们要实现数据双向绑定的第一步,即view->model的绑定。根据之前那个简单的例子看到,我们可以通过input事件实时获取input中的值,接着将通过Object.defineProperty这个方法将data中的text设置为vm的访问器属性。当我们将获取到的input值设置vm.data.text时,通过set方法,实现了数据层的绑定。在这一步,set中要做的操作是更新属性的值。
七、订阅/发布模式(subscribe&publish)
text 属性变化了,set方法触发了,可以通过view层的改变实时改变数据,可是并没有改变文本节点的数据。一个新的知识点:订阅发布模式。
订阅发布模式定义了一种一对多的关系,让多个观察者同时监听一个主题对象,这个主体对象的改变会通知所有观察者对象。
发布者发出通知=>主题对象收到通知并推送给订阅者=>订阅者执行操作
上图为一个简单实例,发布者执行发布命令,所有这个主题的订阅者执行更新操作。接下去我们要做的就是,当set方法触发后,input作为发布者,改变了text属性;而文本节点作为订阅者,在收到消息后执行更新操作。
八、双向绑定的实现
每次new一个新的vue对象时,主要是做了两件事,一件是监听数据:observer(监听数据),第二个是编译HTML,nodeToFragement(id)。
在监听数据的过程中,会为data中的每一个属性生成一个主题对象。
而在编译HTML的过程中,会为每个与数据绑定的相关节点生成一个订阅者watcher,订阅者watcher会将自己订阅到相应属性的dep中。
在前面的方法中已经实现了:修改输入框内容=>再时间回调中修改属性值=>触发属性的set方法。
接下来要做的是发出通知dep.notify=>发出订阅者的uodate方法=>更新视图。
那么如何将watcher添加到关联属性的dep中呢。
编译HTML过程中,为每一个与data关联的节点生成一个watcher,那么watcher中又发生了什么?
在编译HTML的过程中,生成watcher
首先将自己赋给了一个全局变量Dep.target;然后执行了update方法,进而执行了get方法,读取了vm的访问器属性,从而触发了访问器属性的get方法,get方法将相应的watcher添加到对应访问器属性的dep中。再次,获取属性的值,然后更新视图。最后将dep.target设置为空,是因为这是个全局变量也是watcher与dep之间唯一的桥梁,任何时间都只能保证只有一个值。
(其实就是说全局一个主题,每个订阅者和发布者都是通过这个主题进行沟通。当执行代码时,这个主题接受到一个发布通知,通知完所有订阅者,然后注销掉,用于下一个通知发布。啰嗦了一段就是想讲为什么要设置Dep.target = null)。
至此,hello world 双向绑定就基本实现了。文本内容会随输入框内容同步变化,在控制器中修改 vm.text 的值,会同步反映到文本内容中。
The text was updated successfully, but these errors were encountered: