Vue2双向绑定和Vue3双向绑定原理及区别

双向绑定包括: 从视图到的数据更新(通过监听实现),从数据到视图的更新。

Vue响应式原理:

MVVM架构模式

Model 层代表数据模型,定义数据修改和操作的业务逻辑

View 代表UI 组件,它负责将数据模型转化成UI 展现出来

ViewModel 是一个同步View 和 Model的对象

在MVVM架构下,View 和 Model 之间并没有直接的联系,ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。

Vue2实现过程

官方文档

1、把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项

简单双向绑定
<!DOCTYPE html>
 <html>
    <head>
      <meta charset="utf-8">
      <title>标题</title>
    </head>
    <body>
      <input type="text" id="demo" />
      <div id="xxx">{{name}}</div>

      <script type="text/javascript">
        const obj = {};
        Object.defineProperty(obj, 'name', {
          set: function(value) {							   //从数据到视图
            document.getElementById('xxx').innerHTML = value;
            document.getElementById('demo').value = value;
          }
        });
        document.querySelector('#demo').oninput = function(e) {//从视图到数据
          obj.name = e.target.value;
        }
        obj.name = '';
      </script>
    </body>
</html>

2、Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。

在这里插入图片描述
当数据变化时,就会触发其set函数,把需要更新的方法放这里面就实现了从数据到视图的更新
这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。

3、每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染

意思是说,每个组件都把自己需要用到的data作为依赖项,只要有依赖项进行更新操作(监听),就会触发依赖项自己的set函数,通知订阅此data的watcher。watcher监控到它的变化,再告诉组件进行更新操作。

vue2缺陷及解决办法:

由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。
a、Vue 无法检测 property 的添加或移除——通过Vue.set(vm.someObject, ‘b’, 2),或者 vm.$set
b、无法检测数组更改例如 a[1]=0;——同上方法Vue.set(vm.items, indexOfItem, newValue)
c、不能在data里面增加项——初始时写入data,值为空

深入理解请参考博客

  1. 从数据到视图的更新,是需要对数据进行监听劫持,这里我们设置一个监听器Observer来实现对所有数据的监听;
  2. 设置一个订阅者Watcher,收到属性的变化通知并执行相应的函数,从而更新视图;
  3. 设置一个解析器Compiler,解析视图DOM中所有节点的指令,并将模板中的数据进行初始化,然后初始化对应的订阅器。

Vue3实现过程:

1、从一个组件的 data 函数中返回一个普通的 JavaScript 对象

2、Vue 会将该对象包裹在一个带有 get 和 set 处理程序的 Proxy 中。

Proxy 和 Reflect是在 ES6 中引入的,它使 Vue 3 避免了 Vue 早期版本中存在的一些响应性问题。
Proxy,代理,是一个对象,它包装了另一个对象(类似浅拷贝),并允许你拦截对该对象的任何交互。
用法:

let exam = {
    name: "Tom",
    age: 24
}
let handler = {
    get: function(target, key){
        console.log("getting "+key);
        return Reflect.get(target,key);
    },
    set: function(target, key, value){
        console.log("setting "+key+" to "+value)
        Reflect.set(target, key, value);
    }
}
let proxy = new Proxy(exam, handler)
proxy.name = "Jerry"
proxy.name
// setting name to Jerry
// getting name
// "Jerry"

get是读控制,set是写控制

3、包装好proxy后,需要跟踪一个 property(属性) 何时被读取

const dinner = {
  meal: 'tacos'
}

const handler = {
  get(target, property, receiver) {//
    track(target, property)
    return Reflect.get(...arguments)
  }
}

const proxy = new Proxy(dinner, handler)
console.log(proxy.meal)

// tacos

track()函数它将检查当前运行的是哪个effect(文档中翻译为副作用函数),并将其与 target 和 property 记录在一起,这使得vue知道该属性是当前effect的依赖——订阅。

4、在 property 值更改时重新运行这个副作用,为此,需要在代理上使用一个 set 函数

const dinner = {
  meal: 'tacos'
}

const handler = {
  get(target, property, receiver) {
    track(target, property)
    return Reflect.get(...arguments)
  },
  set(target, property, value, receiver) {
    trigger(target, property)
    return Reflect.set(...arguments)
  }
}

const proxy = new Proxy(dinner, handler)
console.log(proxy.meal)

// tacos

通过trigger()函数,去触发以target的property为依赖的effect——发布

具体track和trigger函数实现待完成

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值