# Vue响应式原理解析
首先定义了四个核心的js文件
- 1. observer.js 观察者函数,用来设置data的get和set函数,并且把watcher存放在dep中
- 2. watcher.js 监听者函数,用来设置dep.target开启依赖收集的条件,和触发视图的更新函数
- 3. compile.js 编译者函数,用来编译模版和实例化 watcher 函数
- 4. index.js 入口文件
注意dep函数就是一个壳子,用来存放watcher和触发watcher更新的
首先从index.js开始,定义函数 SelfVue
```js
function SelfVue (options) {
Object.keys(this.data).forEach(function(key) {
self.proxyKeys(key);
//遍历data,给每一个key执行函数 proxyKeys,定义get、set
//这样就可以通过 this.name 来获取data中的name值了
//否则的话必须通过 this.data.name 才能获取
});
observe(this.data); //观察this.data,设置好各种监听的规则
new Compile(options.el, this);//在这里处理编译和调用watcher的函数
options.mounted.call(this); // 所有事情处理好后执行mounted函数
}
```
然后看 observe函数:
```js
defineReactive: function(data, key, val) {
var dep = new Dep();//初始化dep,dep用来存放watcher
Object.defineProperty(data, key, {
get: function getter () {
//只有在watcher中才会设置Dep.target,所以只有在watcher中才会去增加监听
if (Dep.target) {//Dep.target就是保存的Watcher自己
dep.addSub(Dep.target);
}
return val;
},
set: function setter (newVal) {
if (newVal === val) {
return;
}
val = newVal;
dep.notify();
}
});
}
```
然后看watcher
```js
function Watcher(vm, exp, cb) {
this.value = this.get(); // 将自己添加到订阅器的操作
/*
在这里执行this.get(),也就是调用了 this.vm.data[this.exp]
即调用了观察者中的get函数:
首先给Dep.target赋值,在观察者函数中,打开了
if (Dep.target) {
dep.addSub(Dep.target); //所以在这里可以向dep中添加watcher函数
}
*/
}
Watcher.prototype = {
get: function() {
Dep.target = this; // 缓存自己
var value = this.vm.data[this.exp] // 强制执行监听器里的get函数
Dep.target = null; // 添加到 dep 中之后,再释放自己
return value;
}
}
```
这样每次 new watcher的时候就会实例化watcher
然后就会调用this.value = this.get();
然后就会执行 this.vm.data[this.exp]
就会调用观察者函数中的 get方法,由于此时设置了dep.target
所以就会保存watcher到dep中
```js
new Watcher(this.vm, exp, function (value) {
self.updateText(node, value);
});
```
再来看compile.js中是何时触发监听watcher函数的,该文件做了三件事情:
```js
this.fragment = this.nodeToFragment(this.el); //获取挂载元素为代码片段
this.compileElement(this.fragment);//划分该代码片段的类型,执行编译
this.el.appendChild(this.fragment);//挂载该代码片段到html上
```
所以核心代码是compileElement函数:
```js
[].slice.call(childNodes).forEach(function(node) {
var reg = /\{\{(.*)\}\}/;
var text = node.textContent;
if (self.isElementNode(node)) { //v-model指令、v-on:click方法
self.compile(node);
} else if (self.isTextNode(node) && reg.test(text)) {//文本节点
self.compileText(node, reg.exec(text)[1]);
}
if (node.childNodes && node.childNodes.length) {//子节点继续循环遍历
self.compileElement(node);
}
});
```
循环遍历模板代码,按照:文本节点、v-model指令、v-on:click方法做不同的逻辑处理:
但是都会用到该函数
```js
new Watcher(this.vm, exp, function (value) {
self.updateText(node, value);
});
```
如上所述,实例化 Watcher的时候,就是给模板中用到的exp,向dep中增加watcher函数,
而watcher函数包括的方法:更新和get函数。
所以遍历完模板后,实例化 watcher,然后就会执行 watcher 中的get函数,实现监听功能。
```js
Watcher.prototype = {
update: function() {
var value = this.vm.data[this.exp];
var oldVal = this.value;
if (value !== oldVal) {
this.value = value;
this.cb.call(this.vm, value, oldVal);
}
},
get: function() {
Dep.target = this; // 缓存自己
var value = this.vm.data[this.exp] // 强制执行监听器里的get函数
Dep.target = null; // 释放自己
return value;
}
};
```
---
待数据发生变化时,会触发观察者函数中的 set 函数:
```js
set: function setter (newVal) {
if (newVal === val) {
return;
}
val = newVal;
dep.notify();
}
```
然后就会通知dep更新,这里注意的是,如果该值没有在模板中使用,this.sub就是空数组,所以这里通知函数中也不会更新视图:
```js
notify: function() {
//虽然上面data的所有值发生变化的时候会触发set和dep.notify();
//但是在这里只是会循环遍历每个之前监听到的watcher---this.subs
//所以,如果在html中没有用到的数据,即使在methods中使用到了
//在这里也不会触发视图更新
this.subs.forEach(function(sub) {
sub.update();
});
}
```
如果模板中使用了两次data中的title:
<h2>{{title}}</h2>
<h1>{{title}}</h1>
则对data循环后,针对title变量,有两个watcher,存在针对该data值:title的this.sub数组中。
所以如果没有在模板中使用到的data,比如age变量,
在set函数中,由于模板中没有用到-->则不会执行new Watcher-->则不会赋值给dep.target-->则不会给 dep中收集依赖,保存watcher;
在get函数中,由于模板中没有用到,对应的dep.sub数组中就是空数组。所以即使set函数通知了dep.notify函数,也会应为是空数组,导致不会执行循环,也无法触发watcher的更新视图函数

vue响应式原理解析的更多相关文章

  1. vue.js响应式原理解析与实现

    vue.js响应式原理解析与实现 从很久之前就已经接触过了angularjs了,当时就已经了解到,angularjs是通过脏检查来实现数据监测以及页面更新渲染.之后,再接触了vue.js,当时也一度很 ...

  2. 深度解析 Vue 响应式原理

    深度解析 Vue 响应式原理 该文章内容节选自团队的开源项目 InterviewMap.项目目前内容包含了 JS.网络.浏览器相关.性能优化.安全.框架.Git.数据结构.算法等内容,无论是基础还是进 ...

  3. 深入解析vue响应式原理

    摘要:本文主要通过结合vue官方文档及源码,对vue响应式原理进行深入分析. 1.定义 作为vue最独特的特性,响应式可以说是vue的灵魂了,表面上看就是数据发生变化后,对应的界面会重新渲染,那么响应 ...

  4. Vue源码--解读vue响应式原理

    原文链接:https://geniuspeng.github.io/2018/01/05/vue-reactivity/ Vue的官方说明里有深入响应式原理这一节.在此官方也提到过: 当你把一个普通的 ...

  5. 详解Vue响应式原理

    摘要: 搞懂Vue响应式原理! 作者:浪里行舟 原文:深入浅出Vue响应式原理 Fundebug经授权转载,版权归原作者所有. 前言 Vue 最独特的特性之一,是其非侵入性的响应式系统.数据模型仅仅是 ...

  6. vue响应式原理,去掉优化,只看核心

    Vue响应式原理 作为写业务的码农,几乎不必知道原理.但是当你去找工作的时候,可是需要造原子弹的,什么都得知道一些才行.所以找工作之前可以先复习下,只要是关于vue的,必定会问响应式原理. 核心: / ...

  7. 深入Vue响应式原理

    深入Vue.js响应式原理 一.创建一个Vue应用 new Vue({ data() { return { name: 'yjh', }; }, router, store, render: h =& ...

  8. 浅析Vue响应式原理(三)

    Vue响应式原理之defineReactive defineReactive 不论如何,最终响应式数据都要通过defineReactive来实现,实际要借助ES5新增的Object.definePro ...

  9. 浅谈vue响应式原理及发布订阅模式和观察者模式

    一.Vue响应式原理 首先要了解几个概念: 数据响应式:数据模型仅仅是普通的Javascript对象,而我们修改数据时,视图会进行更新,避免了繁琐的DOM操作,提高开发效率. 双向绑定:数据改变,视图 ...

随机推荐

  1. SQL Server 中关于系统库Tempdb总结

    Tempdb系统数据库是一个全局资源,可供连接到SQL Server实例的所有用户使用. 存储的内容项: 1.用户对象 用户对象由用户显示创建.这些对象可以位于用户会话的作用域中,也可以位于创建对象所 ...

  2. centos7双网卡绑定

    # 概念 服务器存在多块网卡时,可以通过bond来实现多块网卡并在一起使用: # 模式 mode 0:load balancing (round-robin) Support:需要Switch支持 & ...

  3. C++实现base64编解码

    Base64是常见的加密算法,代码实现了基于C++的对于base64的编码和解码. 其中注释掉的部分为编码部分,取消注释将解码部分注释掉即可实现编码,反之可以实现解码. #include <st ...

  4. DELPHI6中DSGNINTF.DCU找不到时的解决方法

    https://www.cnblogs.com/gaodu2003/archive/2009/06/04/1495789.html 1.添加 lib\designide.dcp到控件的dpk文件的re ...

  5. Linux下嵌入式Web服务器BOA和CGI编程开发

    **目录**一.环境搭建二.相关配置(部分)三.调试运行四.测试源码参考五.常见错误六.扩展(CCGI,SQLite) # 一.环境搭建操作系统:Ubuntu12.04 LTSboa下载地址(但是我找 ...

  6. (五)pdf的构成之文件体(catalog对象)

    引自:https://blog.csdn.net/steve_cui/article/details/82735039 目录(catalog): 文档目录包含对定义文档内容的其他对象的引用.它还包含声 ...

  7. python_协程

    协程 问题一: 生成器与函数的区别?生成器分阶段的返回多个值,相当于有多个出口(结果): yield ''' yield # 中断.返回函数值 1.只能在函数中使用 2.会暂停函数执行并且返回表达式结 ...

  8. .Net Core WebApi(2)—Swagger

    上一个版本的入门Swagger提示不够完整,这章着重完善和优化 Swagger用于将我们编写的接口自动生成规范化的文档,便于进行测试和对接    一.创建Swagger 1.1  Nuget 安装   ...

  9. 一个超实用的python爬虫功能使用 requests BeautifulSoup

    一个简单的数据爬取的示例 import os,re import requests import random import time from bs4 import BeautifulSoup us ...

  10. guava使用

    对于Guava Cache本身就不多做介绍了,一个非常好用的本地cache lib,可以完全取代自己手动维护ConcurrentHashMap. 背景 目前需要开发一个接口I,对性能要求有非常高的要求 ...