一、什么是双向绑定

我们先从单向绑定切入

单向绑定非常简单,就是把Model绑定到View,当我们用JavaScript代码更新Model时,View就会自动更新

双向绑定就很容易联想到了,在单向绑定的基础上,用户更新了ViewModel的数据也自动被更新了,这种情况就是双向绑定

举个栗子

当用户填写表单时,View的状态就被更新了,如果此时可以自动更新Model的状态,那就相当于我们把ModelView做了双向绑定

关系图如下

二、双向绑定的原理是什么

我们都知道 Vue 是数据双向绑定的框架,双向绑定由三个重要部分构成

  • 数据层(Model):应用的数据及业务逻辑

  • 视图层(View):应用的展示效果,各类UI组件

  • 业务逻辑层(ViewModel):框架封装的核心,它负责将数据与视图关联起来

而上面的这个分层的架构方案,可以用一个专业术语进行称呼:MVVM

这里的控制层的核心功能便是 “数据双向绑定” 。自然,我们只需弄懂它是什么,便可以进一步了解数据绑定的原理

理解ViewModel

它的主要职责就是:

  • 数据变化后更新视图

  • 视图变化后更新数据

当然,它还有两个主要部分组成

  • 监听器(Observer):对所有数据的属性进行监听

  • 解析器(Compiler):对每个元素节点的指令进行扫描跟解析,根据指令模板替换数据,以及绑定相应的更新函数

    三、实现双向绑定

    我们还是以Vue为例,先来看看Vue中的双向绑定流程是什么的

    1. new Vue()首先执行初始化,对data执行响应化处理,这个过程发生Observe

    2. 同时对模板执行编译,找到其中动态绑定的数据,从data中获取并初始化视图,这个过程发生在Compile

    3. 同时定义⼀个更新函数和Watcher,将来对应数据变化时Watcher会调用更新函数

    4. 由于data的某个key在⼀个视图中可能出现多次,所以每个key都需要⼀个管家Dep来管理多个Watcher

    5. 将来data中数据⼀旦发生变化,会首先找到对应的Dep,通知所有Watcher执行更新函数

    流程图如下:

    实现

    先来一个构造函数:执行初始化,对data执行响应化处理

    class Vue {constructor(options) {this.$options = options;this.$data = options.data;// 对data选项做响应式处理observe(this.$data);// 代理data到vm上proxy(this);// 执行编译new Compile(options.el, this);}
    }

    data选项执行响应化具体操作

    function observe(obj) {if (typeof obj !== "object" || obj == null) {return;}new Observer(obj);
    }
    ​
    class Observer {constructor(value) {this.value = value;this.walk(value);}walk(obj) {Object.keys(obj).forEach((key) => {defineReactive(obj, key, obj[key]);});}
    }

    编译Compile

    对每个元素节点的指令进行扫描跟解析,根据指令模板替换数据,以及绑定相应的更新函数

    class Compile {constructor(el, vm) {this.$vm = vm;this.$el = document.querySelector(el);  // 获取domif (this.$el) {this.compile(this.$el);}}compile(el) {const childNodes = el.childNodes; Array.from(childNodes).forEach((node) => { // 遍历子元素if (this.isElement(node)) {   // 判断是否为节点console.log("编译元素" + node.nodeName);} else if (this.isInterpolation(node)) {console.log("编译插值⽂本" + node.textContent);  // 判断是否为插值文本 {{}}}if (node.childNodes && node.childNodes.length > 0) {  // 判断是否有子元素this.compile(node);  // 对子元素进行递归遍历}});}isElement(node) {return node.nodeType == 1;}isInterpolation(node) {return node.nodeType == 3 && /\{\{(.*)\}\}/.test(node.textContent);}
    }

    依赖收集

    视图中会用到data中某key,这称为依赖。同⼀个key可能出现多次,每次都需要收集出来用⼀个Watcher来维护它们,此过程称为依赖收集

    多个Watcher需要⼀个Dep来管理,需要更新时由Dep统⼀通知

    实现思路

    1. defineReactive时为每⼀个key创建⼀个Dep实例

    2. 初始化视图时读取某个key,例如name1,创建⼀个watcher1

    3. 由于触发name1getter方法,便将watcher1添加到name1对应的Dep中

    4. name1更新,setter触发时,便可通过对应Dep通知其管理所有Watcher更新

    // 负责更新视图
    class Watcher {constructor(vm, key, updater) {this.vm = vmthis.key = keythis.updaterFn = updater
    ​// 创建实例时,把当前实例指定到Dep.target静态属性上Dep.target = this// 读一下key,触发getvm[key]// 置空Dep.target = null}
    ​// 未来执行dom更新函数,由dep调用的update() {this.updaterFn.call(this.vm, this.vm[this.key])}
    }

    声明Dep

    class Dep {constructor() {this.deps = [];  // 依赖管理}addDep(dep) {this.deps.push(dep);}notify() { this.deps.forEach((dep) => dep.update());}
    }

    创建watcher时触发getter

    class Watcher {constructor(vm, key, updateFn) {Dep.target = this;this.vm[this.key];Dep.target = null;}
    }

    依赖收集,创建Dep实例

    function defineReactive(obj, key, val) {this.observe(val);const dep = new Dep();Object.defineProperty(obj, key, {get() {Dep.target && dep.addDep(Dep.target);// Dep.target也就是Watcher实例return val;},set(newVal) {if (newVal === val) return;dep.notify(); // 通知dep执行更新方法},});
    }

    ##

浅谈vue双向绑定的原理相关推荐

  1. 浅谈vue双向绑定原理

    简析mvvm框架 目前angular,reat和vue都是mvvm类型的框架 以vue为例 这里的vm 就是vue框架,它相当于中间枢纽的作用,连接着model 和view. 当前台显示的view发生 ...

  2. vue双向绑定的原理

    之前我有个学生在面试的时候,面试官问vue的双向绑定如何实现?学生说用v-module实现.又问那么双向绑定的原理是什么?就回答不上来了,这个offer工资在18k左右,其他问题都回答上来了,如果这个 ...

  3. VUE双向绑定的原理(简单版)+虚拟DOM 节点的创建和更新

    手动敲敲代码,就很容易理解了,供参考 1.以下是VUE双向绑定的原理(简单版) 主要是监听和defineProperty实现简单的双向绑定 <html><head></h ...

  4. Vue双向绑定:原理篇(详细)

    文章目录 前言 什么是响应式 数据劫持 发布者-订阅者模式 模式简介 发布者 Observer 订阅器 dep 订阅者 Watcher 整体流程 初始化data data变为响应式数据 解析模板 收集 ...

  5. 浅聊vue双向绑定原理Object.defineProperty-/-Proxy

    什么是双向绑定呢?vue又是怎么做的我们接下来就聊一聊 什么是双向绑定? 当数据模型data变化时,页面视图会得到响应更新 vue又是怎么做的? vue其实现原理是对data的getter/sette ...

  6. Vue学习笔记--Vue双向绑定实现原理

    我们知道Vue可以实现数据双向绑定,Angular和Vue都是采用的MVVM 模式,意思就是当M(模型层)层数据进行修改时,VM层会监测到变化,并且通知V(视图层)层进行相应的修改,反之修改V层则会通 ...

  7. Vue面试题分享之Vue双向绑定数据原理

    采用数据劫持结合发布-订阅者模式的方式,通过Object.definproperty()来劫持data里面各个属性的setter和getter钩子,在数据变动的时候,触发set方法,监测到数据发生变化 ...

  8. vue双向绑定原理源码解析

    当我们学习angular或者vue的时候,其双向绑定为我们开发带来了诸多便捷,今天我们就来分析一下vue双向绑定的原理. 简易vue源码地址:https://github.com/maxlove123 ...

  9. 浅谈vue 之双向绑定和响应式(vue的响应式)

    初识vue小伙伴通常都会被他的双向绑定所感叹,神奇?方便?而且在不少的面试中也会被面试官问到,上来就是:请问vue双向绑定的原来是什么?我们就来研究研究这是个什么东西: v-model 官方其实已经说 ...

最新文章

  1. 20145202、20145225、20145234 《信息安全系统设计基础》实验五 简单嵌入式WEB 服务器实验...
  2. [react] 什么是浅层渲染?
  3. c语言链表实现数组逆置,数组与链表等顺序表逆置
  4. 集合的get方法中参数从多少开始_源码分析CopyOnWriteArrayList 中的隐藏知识,你Get了吗?...
  5. ppt文字磨砂玻璃效果制作教程
  6. 关于 git pull 和 git pull origin develop 的区别
  7. Win11怎么创建系统映像?
  8. win7替换桌面图标
  9. Codeforces1509.B. TMT Document
  10. 冻结训练的理解与使用
  11. C++ 寻找完数 | Java 完数
  12. WMS多仓库调拨模块设计
  13. [学习笔记]基于ffmpeg的视频解码,输出YUV图像到文件。
  14. 不要轻易使用TerminateThread中止线程
  15. gh60(OK60RGB)刷固件折腾日志(MacOs版)
  16. 计算机病毒与防范 论文,计算机病毒与防范论文
  17. 奇虎360支持Unity引擎 将推3D页游无插件安装
  18. [时间管理]TED-如何掌控你的时间
  19. 基于JAVA社区管理系统计算机毕业设计源码+系统+lw文档+部署
  20. usaco-milk2-pass

热门文章

  1. 服务器处理器(Xeon)和家用处理器(酷睿 锐龙)有什么区别?
  2. CIO如何管理企业业务流程
  3. 2019PMP考试考场规则+答题卡注意事项
  4. 被ASP的小问题难倒!
  5. Python--[项目]机器学习之电影推荐系统[基于物品的协同过滤](代码版)
  6. python好就业么_Python语言就业前景怎么样?好吗?
  7. 查看Mac本机的Python3的安装路径
  8. 从0开始,精通Go语言Rest微服务架构和开发
  9. URL access forbidden for unknown reason svn: E170001: OPTIONS of 403 Forbidden (https://**/**)
  10. 网站的视觉路径和版式设计