关于Vue的源码解析(一)

先上一张vue底层原理关系图

vue底层原理关系图

上图完整的描述了 Vue 运行的机制,首先数据发生改变,就会经过 Data 处理,然后Dep会发出通知(notify),告诉 Watcher 有数据发生了变化,接着 Watcher 会传达给渲染函数跟他说有数据变化了,可以渲染视图了(数据驱动视图),进而渲染函数执行render 方法去更新 VNODE,也就是我们说的虚拟DOM,最后虚拟DOM根据最优算法,去局部更新需要渲染的视图。这里的 Data 就做了我们今天要说的事——数据劫持

一、数据的双向绑定

双向绑定数据响应的原理就是往data的属性调用Object.defineProperty方法去加get,set函数

    var obj = {};
    Object.defineProperty(obj,"name",{
      //Object.defineProperty(obj, prop, descriptor)
      // obj
      // 要在其上定义属性的对象。
      // prop
      // 要定义或修改的属性的名称。
      // descriptor
      // 将被定义或修改的属性描述符。
      get:function(){
        return document.querySelector('#name').innerHTML;
      },
      set:function(val){
        document.querySelector('#name').innerHTML = val;
      }
    })
    obj.name = "luccy"

那么知道vue的数据绑定原理之后,我们尝试下自己写一个vue.js叫KVue.js

创建一个类Kvue,接收的数据为
new Kvue({
data:{...}
})

class KVue{
  constructor(option) { //constructor 是一种用于创建和初始化class创建的对象的特殊方法。
    this.$options = option;

    // 数据响应化
    this.$data = option.data;  //获取data数据
    this.observe(this.$data);  //observe 监听方法
  }
}

observe方法用于监听data里面的数据变化

所以我们在KVued的类中需要创建一个observe方法

  // 监听
  observe(obj){
    if(!obj || typeof obj !== 'object'){  //判断书数据存在且是一个对象
      return;
    }

    // 遍历该对象
    Object.keys(obj).forEach(key =>{  //遍历拿出所有属性
      this.defineReactive(obj,key,obj[key]);  //数据响应化函数
    })
  }

该方法是通过遍历data,给data里面的每一个值都加上get,set的监听即是vue双向绑定的原理

在KVue中创建defineReactive函数,这个方法叫做数据劫持

//  数据响应化
  defineReactive(obj,key,val){    // 可称为数据劫持

    this.observe(val);  //多层遍历,递归解决数据的嵌套

    Object.defineProperty(obj,key,{
      get(){
        return val;
      },
      set(newVal){
        if(newVal === val){
          return;
        }
        val = newVal;
        console.log(`${key}属性更新了:${val}`)
      }
    })
  }

这样就完成了数据响应化的操作即双向绑定

接下来在html中使用我们的KVue.js,并打开浏览器查看

  <body>
    <div>
      <p id="name"></p>
    </div>
  </body>
  <script src="Kvue.js"></script>
  <script>
    // 调用Kvue
    const app = new KVue({
      data:{
        name:'雷神之锤',
        list:{
          litile:'小矮子'
        }
      }
    })
    app.$data.name = "雷神之斧";
    app.$data.list.litile = '大个子';
    /*
      关于为什么是app.$data 而不是 app.data是因为Kvue里面封装的问题
        this.$data = option.data;
        this.observe(this.$data);  //observe 监听方法
    */
  </script>
image.png

二、依赖收集与追踪

找到页面中需要更新的地方,并通知更改

在KVue.js中创建Dep类(用于管理Watcher)和Watcher类(监听器负责更新视图)

// 依赖对象 用来管理Watcher
class Dep {
  constructor(){
    // 这里存放若干依赖(Watcher)
    this.deps = [];
  }
  // 添加依赖方法
  addDep(dep){
    this.deps.push(dep);
  }
  //通知方法  用于通知所有依赖去做更新
  notify(){
    this.deps.forEach(dep => dep.update())
  }
}
// 观察者,监听器:负责更新视图
class watcher {
  constructor(){
    // 将当期watcher实例指定到Dep静态属性target
    Dep.target = this;
  }
  // 更新操作
  update(){
    console.log('属性更新了');
  }
}

然后再模拟创建一下watcher
在KVue类中修改

constructor(option) { //constructor 是一种用于创建和初始化class创建的对象的特殊方法。
    this.$options = option;
    // 数据响应化
    this.$data = option.data;
    this.observe(this.$data);  //observe 监听方法
    
    //模拟watcher创建
    new watcher();
    this.$data.name = '雷神之斧2';
    new watcher();
    this.$data.list.litile = '大个子2'
  }

在遍历data的时候在defineReactive方法中添加依赖

get(){
        Dep.target && dep.addDep(Dep.target);  //添加依赖
        return val;
      },

打开浏览器会发现模拟watcher创建的属性读取了


运行
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 这方面的文章很多,但是我感觉很多写的比较抽象,本文会通过举例更详细的解释。(此文面向的Vue新手们,如果你是个大牛...
    Ivy_2016阅读 15,366评论 8 64
  • vue理解浅谈 一 理解vue的核心理念 使用vue会让人感到身心愉悦,它同时具备angular和react的优点...
    ambeer阅读 24,100评论 2 18
  • 一:什么是闭包?闭包的用处? (1)闭包就是能够读取其他函数内部变量的函数。在本质上,闭包就 是将函数内部和函数外...
    xuguibin阅读 9,510评论 1 52
  • 前言 使用Vue在日常开发中会频繁接触和使用生命周期,在官方文档中是这么解释生命周期的: 每个 Vue 实例在被创...
    心_c2a2阅读 2,230评论 1 8
  • vue概述 在官方文档中,有一句话对Vue的定位说的很明确:Vue.js 的核心是一个允许采用简洁的模板语法来声明...
    li4065阅读 7,185评论 0 25