浅谈Vue的双向绑定

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅谈Vue的双向绑定相关的知识,希望对你有一定的参考价值。

参考技术A 在使用vue的时候给我最大的感受就是双向绑定实在是太方便了吧,这次来谈谈我的理解。

一:MVVM模式;

    说到vue的双向绑定首先联系到的就是MVVM(Model-View-ViewModel)模式了,如下图所示,当试图发生改变的时候传递给VM,再让数据得到更新,当数据发生改变的时候传给VM,使得试图发生改变;

    MVVM模式是通过以下三个核心组件组成,每个都有它自己独特的角色:

         Model  - 包含了业务和验证逻辑的数据模型

         View  - 定义屏幕中View的结构,布局和外观

         ViewModel  - 扮演“View”和“Model”之间的使者,帮忙处理  View  的全部业务逻辑

二、vue数据双向绑定原理

vue的数据双向绑定主要通过Object.defineProperty()方法来进行数据劫持以及发布者-订阅模式来实现的,

vue是怎么实现数据劫持的呢?vue实例话的时候会去遍历所有的属性,给这些属性添加get和set方法进行数据劫持;

以上就是mvvm实现双向绑定的思路了,那么具体怎么实现呢?

我们开头的时候说到了,要想实现数据的双向绑定首先就要通过数据拦截来进行监听数据的改变,这个时候就要设置一个监听器Observer来进行监听,如果属性发生改变的话就告诉订阅者Watcher看看是否需要改变,同时的话订阅者可以有好多个,我们就用一个订阅者管理器(Dep)来管理这些订阅者。紧接着我们还要有个指令解析器来对每个节点进行扫描和解析(解析节点的指令如v-on),把他们初始化成一个订阅器Watcher,并且绑定相应的函数,Watcher会对比前后两个的数值是否发生变化,然后确定是否通知视图进行重新渲染;

以上的图片可以具,体归纳为:

1.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。

2.实现一个订阅者Watcher,可以收到属性的变化通知并执行相应的函数,从而更新视图。

3.实现一个解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。

浅谈Vue之双向绑定

  VUE实现双向数据绑定的原理就是利用了 Object.defineProperty() 这个方法重新定义了对象获取属性值(get)和设置属性值(set)的操作来实现的。先看个例子

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div id="app">
    <h5 id="txtShow"></h5>
    <input type="text" id="txt">
  </div>
  <script>
    // mvvm 分为model(模型) view(视图) viewModel(视图模型)
    //  model 用来存储数据
    //  view  用来展示数据
    //  ViewModel 关联数据,和model实现双向绑定。
    
    // 通过Object.defineProperty 定义一个属性
    //  通过此方法为对象设置属性的时候 对象的属性值会包含一个get和set方法
    //  当修改对象值得时候回触发相应的函数调用
    //  参数一 需要定义属性的对象
    //  参数二 属性名字
    //  参数三 对象属性的修饰内容 
    //    在set方法中做一些处理,执行页面的刷新和回调
    var model = {}
    var v = ‘‘;//存值
    Object.defineProperty(model, ‘txt‘, {
      // 设置属性值
      set: function(val) {
        v = val;
        txtShow.innerHTML = this.txt;
      },
      // 获取属性值
      get: function () {
        return v;
      }
    })

    var txtShow = document.getElementById(‘txtShow‘),
      txt = document.getElementById(‘txt‘);

    txt.onkeyup = function() {
      if (event.keyCode == 13) {
        model.txt = txt.value;
      }
    }


  </script>
</body>
</html>

 

  大家应该都见过Object.defineProperty() ,只是可能个别同志会感觉比较陌生。

  根据MDN web docs 中解释说: Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。

语法

Object.defineProperty(obj, prop, descriptor)

参数

obj
要在其上定义属性的对象。
prop
要定义或修改的属性的名称。
descriptor
将被定义或修改的属性描述符。

返回值

    被传递给函数的对象。

  该方法允许精确添加或修改对象的属性。通过赋值操作添加的普通属性是可枚举的,能够在属性枚举期间呈现出来(for...in 或 Object.keys 方法), 这些属性的值可以被改变,也可以被删除。这个方法允许修改默认的额外选项(或配置)。默认情况下,使用 Object.defineProperty() 添加的属性值是不可修改的。

  

  对象里目前存在的属性描述符有两种主要形式:数据描述符存取描述符数据描述符是一个具有值的属性,该值可能是可写的,也可能不是可写的。存取描述符是由getter-setter函数对描述的属性。描述符必须是这两种形式之一;不能同时是两者。

  数据描述符和存取描述符均具有以下可选键值:

configurable
当且仅当该属性的 configurable 为 true 时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除。默认为 false
enumerable
当且仅当该属性的enumerabletrue时,该属性才能够出现在对象的枚举属性中。默认为 false

数据描述符同时具有以下可选键值

value
该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined
writable
当且仅当该属性的writabletrue时,value才能被赋值运算符改变。默认为 false

存取描述符同时具有以下可选键值

get
一个给属性提供 getter 的方法,如果没有 getter 则为 undefined。当访问该属性时,该方法会被执行,方法执行时没有参数传入,但是会传入this对象(由于继承关系,这里的this并不一定是定义该属性的对象)。
默认为 undefined
set
一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。当属性值修改时,触发执行该方法。该方法将接受唯一参数,即该属性新的参数值。
默认为 undefined
 描述符可同时具有的键值
   configurable  enumerable  value writable  get   set
数据描述符  YES  YES  YES  YES  NO  NO
存取描述符  YES  YES  NO  NO  YES  YES

  如果一个描述符不具有value,writable,get 和 set 任意一个关键字,那么它将被认为是一个数据描述符。如果一个描述符同时有(value或writable)和(get或set)关键字,将会产生一个异常。

  记住,这些选项不一定是自身属性,如果是继承来的也要考虑。为了确认保留这些默认值,你可能要在这之前冻结 Object.prototype,明确指定所有的选项,或者通过 Object.create(null)__proto__属性指向null

  

以上是关于浅谈Vue的双向绑定的主要内容,如果未能解决你的问题,请参考以下文章

vue组件双向绑定key的作用

vue数据双向绑定原理

vue双向绑定数据改为静态数据

Vue3 双向绑定——Proxy

Vue2从入门到精通详解Vue数据双向绑定原理及手动实现双向绑定

Vue3的双向绑定是如何实现的