vue 的双向绑定原理「建议收藏」

vue 的双向绑定原理「建议收藏」vue采用“数据劫持”和“观察者模式(又叫做发布者-订阅者模式)”相结合的方式,通过Object.defineProperty()来劫持各个属性的setter、getter,在数据变动时发布消息给订阅者,触发相应的监听回调。vue的双向绑定原理,分三步:第一步,“数据劫持”:vue用Object.defineProperty()方法实现数据劫持,为每个属性分配一个订阅者集合的管理数组dep; 第二步,“添加观察者”:在编译的时候在该属性的数组dep中添加订阅者,添加方式包括:v

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

目录

一、一句话描述 vue 的双向绑定原理

二、细说 vue 的双向绑定原理

1、vue 2.x 的双向绑定

2、vue 3.x 的双向绑定

3、一个完整的案例


一、一句话描述 vue 的双向绑定原理(vue 的响应式原理)

vue 在实例化的时候,使用 Object.definePropery() 方法Proxy 构造函数,对 data 进行 getter 和 setter 的处理。在组件渲染时,若用到 data 里的某个数据,这个数据就会被依赖收集进 watcher 里。当数据更新,如果这个数据在 watcher 里,就会收到通知并更新,否则不会更新——vue 采用“数据劫持”+“观察者模式(发布者-订阅者模式)”相结合的方式实现了双向绑定——vue 的响应式原理。

【拓展】

“数据劫持”+“观察者模式(发布者-订阅者模式)”:通过 Object.defineProperty() 方法(Vue 2.x)或 ES6 的 Proxy 构造函数(Vue 3.x)来劫持各个属性的 setter、getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

 

二、细说 vue 的双向绑定原理(vue 的响应式原理)

  • 第一步,“数据劫持”:vue 2.x 用 Object.defineProperty() 方法来实现数据劫持,为每个属性分配一个订阅者集合的管理数组 dep;vue 3.x 用 ES6 的 Proxy 构造函数来实现数据劫持。
  • 第二步,“添加订阅者”:在编译的时候在该属性的数组 dep 中添加订阅者,添加方式包括:v-model 会添加一个订阅者,{
    {}} 也会,v-bind 也会,只要用到该属性的指令理论上都会。
  • 第三步,“为 input 添加监听事件”:为 input 添加监听事件,修改值就会为该属性赋值,触发该属性的 set() 方法,在 set() 方法内通知订阅者数组 dep,订阅者数组循环调用各订阅者的 update() 方法更新视图。

1、vue 2.x 的双向绑定

–> 发布者-订阅者模式:

// 订阅者(观察者)
let uid = 0;
class Dep {
  constructor(){
    this.id = uid++;
    this.subs = [];
  }
  addSub(sub){
    this.subs.push(sub);
  }
  removeSub(sub){
    const arr = this.subs,
          item = sub;
    if(arr.length){
      const index = arr.indexOf(item);
      if(index > -1){
        return arr.splice(index, 1);
      }
    }
  }
  depend(){
    if(window.target){
      window.target.addDep(this);
    }
  }
  notify(){
    const subs = this.subs.slice();
    for(let i = 0, len = subs.lengths; i < len; i++){
      subs[i].update();
    }
  }
}

// 发布者(被观察者)(不考虑深度监听)
class Watcher {
  constructor(vm, expOrFn, cb) {
    this.vm = vm;
    this.deps = [];
    this.depIds = new Set();
    this.getter = expOrFn;
    this.cb = cb;
    this.value = this.get();
  }
  get() {
    window.target = this;
    var value = this.getter.call(this.vm, this.vm);
    window.target = undefined;
    return value;
  }
  addDep() {
    const id = dep.id;
    if(!this.depIds.has(id)){
      this.depIds.add(id);
      this.deps.push(dep);
      dep.addSub(this);
    }
  }
  update() {
    console.log("更新, value:", this.value);
  }
}

/* “发布者-订阅者模式”的使用示例 */
// 创建 发布者 实例
var watcher = new Watcher({ x: 1 }, (val) => val);
watcher.get();

// 创建 订阅者 实例
var dep = new Dep();

// 订阅者 监听 发布者 对象
dep.depend();
dep.notify();

–> 数据劫持: 

// 数据劫持
function defineReactive(obj, key, val){
  let dep = new Dep();
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter() {
      dep.depend();
      return value;
    },
    set: function reactiveSetter(newVal) {
      if(val === newVal){
         return;
      }
      val = newVal;
      dep.notify();
    }
  });
}

2、vue 3.x 的双向绑定

vue 3.x 的双向绑定与 vue 2.x 的双向绑定,都采用 发布者-订阅者模式,不同的是 数据劫持 的实现,vue 3.x 采用的是 ES6 的 Proxy 构造函数实现的。

Proxy(data, {
  get(target, key) {
    return target[key];
  },
  set(target, key, value) {
    let val = Reflect.set(target, key, value);
      _that.$dep[key].forEach(item => item.update());
    return val;
  }
})

3、一个完整的案例

<body>
	<div id="demo"></div>
	<input type="text" id="inp">
</body>
<script type="text/javascript">
	var obj = {};
	var demo = document.querySelector('#demo')
	var inp = document.querySelector('#inp')
	Object.defineProperty(obj, 'name', {
		get: function() {
			return val;
		},
		set: function(newVal) { //当该属性被赋值的时候触发
			inp.value = newVal;
			demo.innerHTML = newVal;
		}
	})
	inp.addEventListener('input', function(e) {
		// 给obj的name属性赋值,进而触发该属性的set方法
		obj.name = e.target.value;
	});
	obj.name = 'fei'; //在给obj设置name属性的时候,触发了set这个方法
</script>

 

 

 

参考文件:

使用Proxy实现Vue数据劫持:https://zhuanlan.zhihu.com/p/50547367

用一句话说明 Vuex工作原理:https://zhuanlan.zhihu.com/p/106838529

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/183903.html原文链接:https://javaforall.net

(0)
上一篇 2022年8月31日 上午9:36
下一篇 2022年8月31日 上午9:46


相关推荐

  • qcow2 总结

    qcow2 总结1 qcow2 文件分布对内存不了解的可跳过此部分 MMU 虚拟地址和物理地址 TLB TranslationL 4k 一个 page 需要一个地址存放 4K gt 4B 4G gt 4MB 100 万个页 100 个进程需要 400M 将页表 一级页表 分为 1024 个页表 二级页表 每个表 二级页表 中包含 1024 个 页表项 页表一定要覆盖全部虚拟地址空间 不分级的页表就需要有 100 多万个页表项来映射 而二级分页

    2026年3月19日
    2
  • 如何编写缺陷报告_测试缺陷报告模板

    如何编写缺陷报告_测试缺陷报告模板缺陷报告

    2025年11月30日
    7
  • git的基本使用方法「建议收藏」

    git的基本使用方法「建议收藏」git的基本使用方法什么是git?git是目前世界上最先进的分布式版本控制系统。git与SVN的最主要区别?SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而工作的时候用的都是自己的电脑,所以开始工作之前需要从中央服务器那里获取最新的版本,然后开始工作,工作完后,需要把自己所做的工作推送到中央服务器。集中式版本控制系统必须要联网才能工作,如果在局域网中,有足够的宽带,运行速度…

    2022年6月29日
    26
  • SqlTransaction事务的用法

    SqlTransaction事务的用法使用SqlTransaction实现数据库操作事务 SqlTransaction类是对SQLServer数据库进行事务处理的类,该类的实例由SqlConnection类实例的BeginTransaction方法创建,表示在该数据库连接实例上开始一个数据库事务,创建SqlTransaction类实例后,在程序中使用该实例的Commit方法提交事务,或者使用该类的Rollback方法回滚事…

    2022年6月10日
    31
  • SpringBoot 自动配置原理[通俗易懂]

    SpringBoot 自动配置原理[通俗易懂]创建项目通过SpringInitialize创建SpringBoot项目而接下来要说的是关于配置文件的事情。关乎配置文件可以参考官方文档。对于配置文件来说到底在配置文件里面可以进行配置那些内容,自动配置的原理又是什么东西呢?自动配置原理在SpringBoot启动的时候加载主配置类,开启了自动配置的功能,通过@EnableAutoConfiguration注解开启自动配置的功能。@Im…

    2022年6月17日
    25
  • 基于51单片机智能小车的设计与实现转弯避障_基于单片机的智能小车设计

    基于51单片机智能小车的设计与实现转弯避障_基于单片机的智能小车设计0引言学习智能小车系统,有助于提高搭建系统的能力和对自动控制技术的理解。智能小车是一个较为完整的智能化系统,而智能化的研究已成为我国追赶世界科技水平的重要任务。智能小车有它特有的特点:成本低,涉及的知识面广,易于拓展[1]。整个智能小车系统作为一个完整的系统,从它的原理图的实现到实物的完成的过程,不仅需要深厚的电子方面的知识,还有对电路实现的良好掌握,对于培养学生的实践能力都有重要的意义。智能小车…

    2022年10月17日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号