work_work

双向数据绑定

https://www.cnblogs.com/kidney/p/6052935.html

 

<!DOCTYPE html>

<html lang="en">

<head>

  <meta charset="UTF-8">

  <title>forvue</title>

</head>

<body>

  <input type="text" id="textInput">

  输入:<span id="textSpan"></span>

  <script>

    var obj = {},

        textInput = document.querySelector('#textInput'),

        textSpan = document.querySelector('#textSpan');

 

    Object.defineProperty(obj, 'foo', {

      set: function (newValue) {

        textInput.value = newValue;

        textSpan.innerHTML = newValue;

      }

    });

 

    textInput.addEventListener('keyup', function (e) {

        obj.foo = e.target.value;

    });

 

  </script>

</body>

</html>

 

 

——

Object.defineProperty方法允许通过属性描述对象,定义或修改一个属性,然后返回修改后的对象,它的用法如下。

 

 

 var obj = {};

    var a = Object.defineProperty(obj, 'p', {

        value: 123

    })

    console.log(a) // {p: 123}

 

———

 

 访问器属性的"值"比较特殊,读取或设置访问器属性的值,实际上是调用其内部特性:get和set函数。

       obj.hello // 读取属性,就是调用get函数并返回get函数的返回值

       obj.hello = "abc" // 为属性赋值,就是调用set函数,赋值其实是传参 

————

DocumentFragment

       DocumentFragment(文档片段)可以看作节点容器,它可以包含多个子节点,当我们将它插入到 DOM 中时,只有它的子节点会插入目标节点,所以把它看作一组节点的容器。使用 DocumentFragment 处理节点,速度和性能远远优于直接操作 DOM。Vue 进行编译时,就是将挂载目标的所有子节点劫持(真的是劫持,通过 append 方法,DOM 中的节点会被自动删除)到 DocumentFragment 中,经过一番处理后,再将 DocumentFragment 整体返回插入挂载目标。

————

 

 

实现思路:当我们在输入框输入数据的时候,首先触发 input 事件(或者 keyup、change 事件),在相应的事件处理程序中,我们获取输入框的 value 并赋值给 vm 实例的 text 属性。我们会利用 defineProperty 将 data 中的 text 设置为 vm 的访问器属性,因此给 vm.text 赋值,就会触发 set 方法。在 set 方法中主要做两件事,第一是更新属性的值.

   text 属性变化了,set 方法触发了,但是文本节点的内容没有变化。如何让同样绑定到 text 的文本节点也同步变化呢?这里又有一个知识点:订阅发布模式。【       发布者发出通知 => 主题对象收到通知并推送给订阅者 => 订阅者执行相应操作】

 

       回顾一下,每当 new 一个 Vue,主要做了两件事:第一个是监听数据:observe(data),第二个是编译 HTML:nodeToFragement(id)。

 

我们已经实现:修改输入框内容 => 在事件回调函数中修改属性值 => 触发属性的 set 方法。

       接下来我们要实现的是:发出通知 dep.notify() => 触发订阅者的 update 方法 => 更新视图。

       这里的关键逻辑是:如何将 watcher 添加到关联属性的 dep 中。

———

 

Vue.use()方法给插件提供了一个注入到 Vue 中的方法,它会调用插件的install方法,该方法在src/install.js中:

    

        将 router 实例挂载到 $router 上,由是我们可以在 vue 文件中通过 this.$router 访问到路有对象

        Object.defineProperty(Vue.prototype, '$router', {

        get () { return this._routerRoot._router }

        })

 

        // 将 route 实例挂载到 $route 上,同上

        Object.defineProperty(Vue.prototype, '$route', {

        get () { return this._routerRoot._route }

        })

上一篇:深入理解 Object.defineProperty


下一篇:用JS模仿VUE实现响应式对象