Vue数据的双向绑定

前言

什么是数据双向绑定? 

  Vue使用的是一个MVVM框架,即数据双向绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化。这也算是vue的精髓之处了。值得注意的是,我们所说的数据双向绑定,一定是对于UI控件来说的,非UI控件不会涉及到数据双向绑定。

为什么要实现数据的双向绑定

在Vue中,如果使用Vuex,实际上数据还是单向的,之所以说是数据双向绑定,这是对于的UI控件来说,对于我们处理表单,Vue的双向数据绑定用起来就特别舒服了。

  即两者并不互斥, 在全局性数据流使用单向,方便跟踪; 局部性数据流使用双向,简单易操作。

如何实现双向绑定?

Vue是通过“数据劫持”+“发布-订阅模式”实现数据的双向绑定的。

“订阅-发布”模式:

其中主要包括两个类:Dep类、Watcher类

Watcher:用于订阅事件。该类中主要包含: 我们将实例化的一个个Wacher对象比作一个个的顾客

  1. 在构造函数中创建一个回调(其中包含着根据最新的数据重新渲染界面的方法)。 因为回调中包含了渲染页面的方法,我们就将回调比作顾客想要做某件事的方法(例如看书的方法)
  2. update:在这个方法中,可以拿到最新的数据,然后触发回调。(该方法供给Dep的notify方法来控制调用执行) 将获取最新数据比作拿到书,触发回调比作用上面的看书的方法来看书

Dep:主要作用是进行依赖收集触发所收集的依赖。该类中主要包含: 我们将Dep比作一个咖啡馆

  1. [ ] :一个数组,专门存放所有的订阅者信息。这个数组中包含了一个个的订阅信息,就像咖啡馆坐着一个个想要看书、聊天、玩游戏的人,他们知道自己想做什么,但是要等到notify方法执行的时候,轮到自己了才可以做
  2. add:向数组添加订阅。 比作向咖啡馆拉有事要做的人,让他们在咖啡馆做
  3. notify:循环触发数组的每个订阅信息,向DOM发布通知(其中就包含执行每个订阅的update和保存在其中的回调函数)。让每桌的顾客,按顺序地来做他们想做的事。第一桌的顾客先看书,看完第二桌的顾客去聊天,聊完第三桌的顾客去玩游戏。

简单的模拟一下订阅发布的实现过程,带大家更好的理解一下:

// 收集依赖、订阅依赖
class Dep{  // 酒吧
    constructor(){
        // 这个 subs 数组,用来存放所有的订阅者的信息
        this.subs = [];  // 迪迦、雷欧、泰罗一会会被拽进来,因为他们有事要和地球人做
    }

    // 向 subs 数组中,添加订阅者的信息
    addSub(watcher){
        this.subs.push(watcher);  // 一会就是通过这个方法把他们仨拽进去的
    }

    // 发布通知的方法
    notify(){
        this.subs.forEach((watcher)=>watcher.update());  // 循环遍历数组中的对象,让这三个奥特曼依次执行他们的 update 方法,也就让他们依次拿着他们得到的东西去做他们想做的事 注意!东西不是在这得到的,是在 update 方法中得到的
    }
}

// 订阅者的类 每实例化一个对象,就可以得到一个取数据来渲染的 Dom  就可以得到一个有事要做的奥特曼
class Watcher {
    constructor(cb){
        this.cb = cb;  // 这里面用于保存每个奥特曼想做的事,例如迪迦的回调里面说他想看书,那就把看书这件事保存进去
    }

    // 调用回调的方法
    update(){
        this.cb();  // 执行回调,在这里会得到最新的数据,这个方法由notify调用。会把迪迦想看的书给他,然后告诉迪迦,去看你的书吧。这个方法交给酒吧的notify方法,让notify这个方法告诉每个奥特曼,该谁去做自己想做的事了
    }
}

const w1 = new Watcher(()=>{
    // 想做的事
    console.log("我是迪迦,我想看会地球的书~");
})
const w2 = new Watcher(()=>{
    console.log("我是泰罗,我想和地球人聊会天~");
})
const w3 = new Watcher(()=>{
    console.log("我是雷欧,我想和地球人打会游戏~");
})

// 建个酒吧
const dep = new Dep();
// 把迪迦拽进去
dep.addSub(w1);
// 把泰罗拽进去
dep.addSub(w2);
// 把雷欧拽进去
dep.addSub(w3);

dep.notify();  // 执行notify方法,让他们依次得到需要的书、人、手机,然后去做自己想做的事。

这里暂时没有细说数据劫持的过程,只是一笔带过,大致的回顾一下:

先说一下Watcher的作用,将“获取数据”和“用新数据渲染Dom的方法”封装到一个订阅事件中。Dep通过add方法添加订阅事件到数组中,在调用Dep实例对象的notify方法时,拿着获取到的最新数据到页面去渲染。

整个数变化到渲染的过程,大致就是:

首先通过数据劫持监听data的数据变化,一旦监听到了数据发生变化,订阅发布开始获取数据,然后调用Dep的notify方法发布通知到每个订阅,订阅根据最新的数据渲染Dom。

这是数据从data到view的过程。从view到data相对简单一些,只需要借助Object.defineProperty的set,即可以获取页面变化的数据,然后将这个数据更新到data中,再渲染到需要的地方。

这是本人的一些理解,如有错误请及时指出,定及时更正,谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

麦田里的POLO桔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值