实现一个简易的vue

image

1./compiler ⽬目录是编译模版;

2./core ⽬目录是 Vue.js 的核⼼心(也是后⾯面的重点);

3./platforms ⽬目录是针对核⼼心模块的 ‘平台’ 模块;

4./server ⽬目录是处理理服务端渲染;

5./sfc ⽬目录处理理单⽂文件 .vue;

6./shared ⽬目录提供全局⽤用到的⼯工具函数。

Vue.js 的组成是由 core + 对应的 ‘平台’ 补充代码构成(独立构建和运行时构建 只是 platforms 下 web 平台的两种选择)。


image

vue的双向数据绑定

双向绑定(响应式原理)所涉及到的技术

1. Object.defineProperty
2. Observer
3. Watcher
4. Dep
5. Directive

1. Object.defineProperty

var obj = {};
var a;
Object.defineProperty(obj,'a',{
  get: function(){
    console.log('get val');
    return a;
  },
  set: function(newVal){
    console.log('set val:' + newVal);
    a = newVal;
  }
});
obj.a // get val;   相当于<span>{{a}}</span>
obj.a = '111'; // set val:111  相当于<input v-model="a">
image

setter 触发消息到 Watcher watcher帮忙告诉 Directive 更新DOM,DOM中修改了数据 也会通知给 Watcher,watcher 帮忙修改数据。

2. Observer

观察者模式是软件设计模式的一种。
在此种模式中,一个目标对象管理所有相依于它的观 察者对象,并且在它本身的状态改变时主动发出通知。
这通常透过呼叫各观察者所提供的 方法来实现。此种模式通常被用来实时事件处理系统。
订阅者模式涉及三个对象:
发布者、主题对象、订阅者,三个对象间的是一对多的关系,
每当主题对象状态发生改变时,其相关依赖对象都会得到通知,并被自动更新。
看一个简单的示例:
image
image

vue里边怎么操作的呢? vue observer

image

image

image
  1. watcher
image
image
  1. Dep
image
  1. Directive
image
image

image
image

弄明白原理和架构之后,我们来实现一个简单的vue双向数据绑定

image

1.这个Vue是从哪里来的呢?

image

是通过上述方法实例化的一个对象;但是里边有两个未知生物 observe ? Compile?
image

observe中写的是双向绑定的核心原理就是Object.defineProperty

通过set,get来设置值与获取值

把text属性绑定到vue实例上面去使用

那其中的Dep又是什么呢?

image

添加订阅者跟通知订阅更新

再来看一下Compile中写的什么吧

function Compile(node, vm) {
  if (node) {
    this.$frag = this.nodeToFragment(node, vm);
    return this.$frag;
  }
}
Compile.prototype = {
  nodeToFragment: function (node, vm) {
    var self = this;
    var frag = document.createDocumentFragment(); // 创建一段html文档片段
    var child;

    while (child = node.firstChild) {
      self.compileElement(child, vm);
      frag.append(child); // 将所有子节点添加到fragment中
    }
    return frag;
  },
  compileElement: function (node, vm) {
    var reg = /\{\{(.*)\}\}/;

    //节点类型为元素
    if (node.nodeType === 1) {
      var attr = node.attributes;
      // 解析属性
      for (var i = 0; i < attr.length; i++) {
        if (attr[i].nodeName == 'v-model') {
          var name = attr[i].nodeValue; // 获取v-model绑定的属性名
          node.addEventListener('input', function (e) {
            // 给相应的data属性赋值,进而触发该属性的set方法
            // 触发set vm[name]
            vm[name] = e.target.value;
          });
          // node.value = vm[name]; // 将data的值赋给该node
          new Watcher(vm, node, name, 'value');
        }
      };
    }
    //节点类型为text
    if (node.nodeType === 3) {
      if (reg.test(node.nodeValue)) {
        var name = RegExp.$1; // 获取匹配到的字符串
        name = name.trim();
        // node.nodeValue = vm[name]; // 将data的值赋给该node
        new Watcher(vm, node, name, 'nodeValue');
      }
    }
  },
}

哦,原来Compile中是渲染html的啊。其中的Watcher是不是监控节点变化,然后给Dep通知的呢?

function Watcher(vm, node, name, type) {
    Dep.target = this;
    this.name = name; //text
    this.node = node; // 节点
    this.vm = vm; // vue实例
    this.type = type; //nodeValue 当前节点的值
    this.update();
    Dep.target = null;
}

Watcher.prototype = {
    update: function() {
        this.get();
        var batcher = new Batcher();
        batcher.push(this);
        // this.node[this.type] = this.value; // 订阅者执行相应操作
    },
    cb:function(){
        this.node[this.type] = this.value; // 订阅者执行相应操作
    },
    // 获取data的属性值
    get: function() {
        this.value = this.vm[this.name]; //触发相应属性的get
    }
}

哎呦,咱们猜对了呢,这样双向数据绑定马上就要完成了,只剩一个Vue.nextTick()的地方了

/**
 * 批处理构造函数
 * @constructor
 */
function Batcher() {
    this.reset();
}

/**
 * 批处理重置
 */
Batcher.prototype.reset = function () {
    this.has = {};
    this.queue = [];
    this.waiting = false;
};

/**
 * 将事件添加到队列中
 * @param job {Watcher} watcher事件
 */
Batcher.prototype.push = function (job) {
    if (!this.has[job.name]) {
        this.queue.push(job);
        this.has[job.name] = job;
        if (!this.waiting) {
            this.waiting = true;
            setTimeout(() => {
                this.flush();
            });
        }
    }
};

/**
 * 执行并清空事件队列
 */
Batcher.prototype.flush = function () {
    this.queue.forEach((job) => {
        job.cb();
    });
    this.reset();
};

看完后是不是觉得超简单呢?

vue3版本将做出巨大的变化,把Dep跟Watcher都干掉了,html直接跟数据进行绑定,等vue3出来后,在写一篇关于vue的文章吧

看完后能帮我点个赞吗?

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

推荐阅读更多精彩内容

  • 深入解析vue 1实现原理,并实现vue双向数据绑定模型vueImitate,此模型(vueImitate)只适用...
    e_payne阅读 7,218评论 0 5
  • vue理解浅谈 一 理解vue的核心理念 使用vue会让人感到身心愉悦,它同时具备angular和react的优点...
    ambeer阅读 24,133评论 2 18
  • 这方面的文章很多,但是我感觉很多写的比较抽象,本文会通过举例更详细的解释。(此文面向的Vue新手们,如果你是个大牛...
    Ivy_2016阅读 15,393评论 8 64
  • 前言 听到XCTest, 可能很多人感到生疏,没用过,其实并没那么难,还是挺容易上手,自己写一些测试用例会能更好的...
    ShawnDu阅读 1,943评论 1 1
  • 少小离家茫然,努力自立自强 每当日落黄昏,思绪坠落眼眶 儿时门前树上,孤村日落烟残 红柳杉白玉兰,大水井此水寒 几...
    刘郎阅读 392评论 5 3