• Vue双向数据绑定实现原理


    https://zendq1998.github.io/2018/04/12/vue%E5%8F%8C%E5%90%91%E6%95%B0%E6%8D%AE%E7%BB%91%E5%AE%9A%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86/

          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

  • 相关阅读:
    时间单位的档案
    Linux中表示“时间”的结构体和相关函数
    linux 下如何给用户添加权限
    C++中虚函数的作用浅析
    C语言中strstr函数
    测试环境下将centos6.8升级到centos7的操作记录(转)
    CURL常用命令(转)
    Centos7管理selinux及使用firewalld管理防火墙
    UML类图几种关系的总结
    linux下面覆盖文件,如何实现直接覆盖,不提示
  • 原文地址:https://www.cnblogs.com/xufeimei/p/10064760.html
Copyright © 2020-2023  润新知