Vue.js 中的数据双向绑定是如何实现的?

Vue.js 中的数据双向绑定是如何实现的?

Vue.js 是一款流行的前端框架,它的核心功能之一是数据双向绑定。本文将介绍 Vue.js 中数据双向绑定的实现原理,并附上相关代码实例。

在这里插入图片描述

什么是数据双向绑定?

在传统的前端开发中,当用户在界面上修改数据时,需要手动更新数据模型,反之亦然。这种方式不仅繁琐,而且容易出错。数据双向绑定可以解决这个问题。它是一种自动同步数据模型和界面的机制,即当数据模型发生变化时,界面会自动更新,反之亦然。

Vue.js 中的数据双向绑定实现原理

Vue.js 中的数据双向绑定是通过数据劫持和发布-订阅模式来实现的。

数据劫持

Vue.js 中的数据劫持是通过 Object.defineProperty 方法来实现的。它可以在一个对象上定义一个新属性,或者修改一个已有属性,并指定该属性的一些特性,例如值、可枚举性、可写性和可配置性等。

在 Vue.js 中,当一个组件创建时,它会遍历所有的属性,对于其中的对象类型,会递归地对其做数据劫持。例如:

function defineReactive(obj, key, val) {
  Object.defineProperty(obj, key, {
    get: function() {
      console.log(`获取 ${key}: ${val}`);
      return val;
    },
    set: function(newVal) {
      console.log(`设置 ${key}: ${newVal}`);
      val = newVal;
    }
  })
}

const data = { name: 'Tom', age: 18 };
defineReactive(data, 'name', 'Tom');
defineReactive(data, 'age', 18);

data.name; // 获取 name: Tom
data.age; // 获取 age: 18

data.name = 'Jerry'; // 设置 name: Jerry
data.age = 20; // 设置 age: 20

在上面的代码中,defineReactive 函数接收三个参数,分别是要做数据劫持的对象、属性名和属性值。在 defineReactive 函数中,使用 Object.defineProperty 方法来定义对象的属性,并为其设置 getset 方法。当获取属性值时,会触发 get 方法,当设置属性值时,会触发 set 方法。

通过这种方式,Vue.js 可以监听到数据模型的变化,并及时更新界面。

发布-订阅模式

Vue.js 中的发布-订阅模式是通过一个事件中心来实现的。事件中心是一个全局的事件管理器,用于管理所有的事件监听和触发。在 Vue.js 中,事件中心被封装在 Vue 对象的原型上,即 Vue.prototype.$emitVue.prototype.$on 方法。

$emit 方法用于触发一个事件,并将数据传递给所有订阅该事件的回调函数。例如:

const eventBus = new Vue();

eventBus.$on('hello', function(data) {
  console.log(`收到 hello 事件,数据为 ${data}`);
});

eventBus.$emit('hello', 'world'); // 收到 hello 事件,数据为 world

在上面的代码中,我们创建了一个事件中心 eventBus,并使用 $on 方法订阅了一个名为 hello 的事件,当该事件被触发时,会执行回调函数并打印出数据。然后,我们使用 $emit 方法触发了一个 hello 事件,并将数据传递给回调函数。

通过发布-订阅模式,Vue.js 可以监听到数据模型的变化,并及时更新界面。

结合数据劫持和发布-订阅模式实现数据双向绑定

在 Vue.js 中,数据双向绑定是通过结合数据劫持和发布-订阅模式来实现的。具体实现步骤如下:

  1. 创建一个 Observer 对象,用于对数据模型进行数据劫持。
  2. 创建一个 Dep 对象,用于管理所有的订阅者。
  3. 创建一个 Watcher 对象,用于订阅数据模型的变化。
  4. Watcher 对象添加到 Dep 对象中。
  5. 当数据模型发生变化时,Observer 对象会通过 Dep 对象通知所有的订阅者,订阅者会自动更新界面。

下面是一个简单的实现示例:

// Observer 对象,用于对数据模型进行数据劫持
function Observer(data) {
  this.data = data;
  this.walk(data);
}

Observer.prototype = {
  walk: function(data) {
    var self = this;
    Object.keys(data).forEach(function(key) {
      self.defineReactive(data, key, data[key]);
    });
  },
  defineReactive: function(data, key, val) {
    var dep = new Dep();

    Object.defineProperty(data, key, {
      enumerable: true,
      configurable: false,
      get: function() {
        if (Dep.target) {
          dep.addSub(Dep.target);
        }
        return val;
      },
      set: function(newVal) {
        if (newVal === val) {
          return;
        }
        val = newVal;
        dep.notify();
      }
    });
  }
};

// Dep 对象,用于管理所有的订阅者
function Dep() {
  this.subs = [];
}

Dep.prototype = {
  addSub: function(sub) {
    this.subs.push(sub);
  },
  notify: function() {
    this.subs.forEach(function(sub) {
      sub.update();
    });
  }
};

Dep.target = null;

// Watcher 对象,用于订阅数据模型的变化
function Watcher(vm, exp, cb) {
  this.vm = vm;
  this.exp = exp;
  this.cb = cb;

  this.value = this.get();
}

Watcher.prototype = {
  update: function() {
    var value = this.vm.$data[this.exp];
    var oldValue = this.value;
    if (value !== oldValue) {
      this.value = value;
      this.cb.call(this.vm, value, oldValue);
    }
  },
  get: function() {
    Dep.target = this;
    var value = this.vm.$data[this.exp];
    Dep.target = null;
    return value;
  }
};

在上面的代码中,我们定义了 ObserverDepWatcher 三个对象。Observer 对象用于对数据模型进行数据劫持,Dep 对象用于管理所有的订阅者,Watcher 对象用于订阅数据模型的变化。

Observer 对象中,我们使用 defineReactive 方法对数据模型进行数据劫持,并为其设置 getset 方法。在 get 方法中,我们将订阅者添加到 Dep 对象中,以便在数据发生变化时可以通知到所有的订阅者。在 set 方法中,我们将新值赋给数据模型,并通过 Dep 对象通知所有的订阅者。

Dep 对象中,我们使用 addSub 方法将订阅者添加到订阅者列表中,使用 notify 方法通知所有的订阅者。

Watcher 对象中,我们使用 update 方法更新界面,并将新值和旧值传递给回调函数。在 get 方法中,我们将当前订阅者添加到 Dep 对象中,并获取数据模型的值。

通过以上实现,Vue.js 可以自动同步数据模型和界面,并实现数据双向绑定。下面是一个简单的使用示例:

// 创建 Vue 实例
var vm = new Vue({
  el: '#app',
  data: {
    message: 'Hello, Vue.js!'
  }
});

// 订阅数据模型的变化
new Watcher(vm, 'message', function(value, oldValue) {
  console.log(`数据模型从 ${oldValue} 变为 ${value}`);
});

// 修改数据模型
vm.$data.message = 'Hello, World!'; // 数据模型从 Hello, Vue.js! 变为 Hello, World!

在上面的代码中,我们创建了一个 Vue 实例,并定义了一个名为 message 的数据模型。然后,我们创建了一个订阅者,用于监听数据模型的变化,并在控制台打印出新值和旧值。最后,我们修改了 message 数据模型的值,触发了数据劫持和发布-订阅模式,订阅者自动更新界面。

总结

数据双向绑定是 Vue.js 的核心功能之一,它可以自动同步数据模型和界面,提高开发效率和代码质量。在 Vue.js 中,数据双向绑定是通过结合数据劫持和发布-订阅模式来实现的。在数据劫持中,Vue.js 使用 Object.defineProperty 方法对数据模型进行监听;在发布-订阅模式中,Vue.js 使用一个事件中心来管理所有的事件监听和触发。通过这两种技术的结合,Vue.js 实现了数据双向绑定,为前端开发带来了很大的便利。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/27004.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

智能应用搭建平台——LCHub低代码表单 vs 流程表单 vs 仪表盘

1. LCHub低代码如何选择 「流程表单」:填报数据,并带有流程审批功能,适合报销、请假申请或其他工作流; 「表单」:填报数据,并带有数据协作功能,如修改、删除、导入、导出,并可以给不同的人不同的管理权限; 「仪表盘」:数据分析处理、结果展示功能,如数据汇总、趋…

JavaSSM笔记(一)

**建议:**对Java开发还不是很熟悉的同学,最好先花费半个月到一个月时间大量地去编写小项目,不推荐一口气学完,后面的内容相比前面的内容几乎是降维打击,一口气学完很容易忘记之前所学的基础知识,尤其是Java…

Python--注释

Python--注释 <font size4, colorblue> 一、Python中注释的形式<font size4, colorblue> 1、单行注释&#xff1a;使用“#”符号注释<font size4, colorblue> 2、多行注释&#xff1a;使用一对三个英文单引号注释<font size4, colorblue> 3、多行注释&…

通用文字识别OCR 之实现数字化教材

引言 通用文字 OCR 识别 API 是一种功能强大的服务&#xff0c;可用于多场景、多语种的整图文字检测和识别&#xff0c;通过将OCR技术应用于学校环境&#xff0c;可以实现教育资源的数字化和学习过程的自动化。 本文将探讨通用文字识别OCR 在学校的实际应用&#xff0c;希望对…

如何在 JavaScript 中创建自定义警告框

本文将介绍如何使用 jQuery UI、SweetAlert2 和自定义警报功能在 JavaScript 中创建自定义警报框。 使用 jQuery UI 创建自定义警告框 我们可以使用 jQuery UI 来模仿 JavaScript 本机 alert() 函数的功能。 尽管 jQuery UI 有很多 API&#xff0c;您可以使用它的 dialog() AP…

基于摄影测量的三维重建【终极指南】

我们生活的时代非常令人兴奋&#xff0c;如果你对 3D 东西感兴趣&#xff0c;更是如此。 我们有能力使用任何相机&#xff0c;从感兴趣的物体中捕捉一些图像数据&#xff0c;并在眨眼间将它们变成 3D 资产&#xff01; 这种通过简单的数据采集阶段进行的 3D 重建过程是许多行业…

泰克AFG31000系列任意波函数发生器应用

模拟电路检定 这是一个模拟世界。所有物理量均使用模拟信号捕获和表示。因此&#xff0c;需要检定放大器、滤波器和转换器等模拟电路的性能。 InstaView? 技术避免在阻抗不匹配的 DUT 上增加的波形不确定性频率范围为 25 MHz 至 250 MHz由于信号保真度高&#xff0c;无需使…

# 车载软件架构 —— 闲聊几句AUTOSAR OS(三)

我是穿拖鞋的汉子,魔都中坚持长期主义的工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 没有人关注你。也无需有人关注你。你必须承认自己的价值,你不能站在他人的角度来反对自己。人生在世,最怕的就是把别人的眼光当成自己生活的唯一标准。到最…

SpringBoot整合OSS文件上传

一、注册阿里云账号并开通OSS服务 1、登录阿里云账号 2、创建一个bucket 3、创建子用户 对自用户分配权限&#xff0c;打开操作OSS的全部权限&#xff08;也可根据业务需求进行更改&#xff09; 4、配置上传跨域规则 任何来源: *允许方法: POST任何请求头Headers: * 二、…

sklearn中的roc_auc_score(二分类或多分类)

官方API地址&#xff1a; sklearn.metrics.roc_auc_score — scikit-learn 1.2.2 documentationExamples using sklearn.metrics.roc_auc_score: Release Highlights for scikit-learn 0.22 Release Highlights for scikit-learn 0.22 Probability Calibration curves Probabi…

如何查询期刊的SCI分区

好消息是CSDN AI写作助手上线了 我不用自己一个字一个字去写SCI分区是啥&#xff08;x&#xff09; 然而—— 麻了还是自己写吧&#xff0c; 在人工智能这条路上&#xff0c;CSDN还是需要努力。 简单来说&#xff0c;我们做科研、发文章&#xff0c;肯定是需要比较的 谁的…

创客匠人CEO蒋洪波:用门店思维做直播

互联网时代&#xff0c;转型线上做知识付费成为教育培训行业的主流&#xff0c;直播教学成为新型的教学模式受到了广泛认可。很多老师在线下培训深耕多年&#xff0c;知识储备丰富&#xff0c;但想要转型线上又缺少方法&#xff0c;缺少去改变的欲望&#xff0c;怕转型做线上直…

docker安装golang

最近玩 docker 比较多&#xff0c;试试安装 golang 操作系统&#xff1a;Linux 第一步 先看一下镜像&#xff1a; docker images 看一下我们目前的镜像中&#xff0c;是不是有go 如果有&#xff0c;版本不合适等&#xff0c;可以考虑删除&#xff0c;重新安装&#xff0c;也…

Linux之进程间通信——管道

文章目录 前言一、进程间通信1.概念2.目的3.进程间通信分类 二、管道1.管道介绍2.管道分类1.匿名管道pipi创建管道文件&#xff0c;打开读写端fork子进程关闭父进程的读取端&#xff0c;关闭子进程的写入端读写特征管道特征 2.命名管道mkfifo创建管道文件删除管道文件通信 三、…

Blindly Assess Image Quality in the Wild Guided by ASelf-Adaptive Hyper Network

Abstract 真实失真图像的盲图像质量评估(BIQA)一直是一个具有挑战性的问题&#xff0c;因为在野外采集的图像包含各种各样的内容和各种类型的失真。目前绝大多数的BIQA方法都专注于如何预测合成图像的质量&#xff0c;但当应用于真实世界的失真图像时却失败了。为了应对这一挑…

一站式完成车牌识别任务:从模型优化到端侧部署

交通领域的应用智能化不断往纵深发展&#xff0c;其中最为成熟的车牌识别早已融入人们的日常生活之中&#xff0c;在高速公路电子收费系统、停车场等场景中随处可见。一些企业在具体业务中倾向采用开源方案降低研发成本&#xff0c;但现有公开的方案中少有完成端到端的车牌应用…

DMBOK知识梳理for CDGA/CDGP——第三章数据治理

关 注gzh“大数据食铁兽” 回复“知识点”获取《DMBOK知识梳理for CDGA/CDGP》常考知识点&#xff08;第三章数据治理&#xff09; 第三章 数据治理 第三章在是CDGA|CDGP考试的重点考核章节之一&#xff0c;知识点比较密集&#xff0c;本章重点为语境关系图及数据治理概念…

给电脑重装系统的时间需要多久才能装好

在进行电脑重装系统时&#xff0c;如果遇到系统安装时间过长的情况&#xff0c;可能会引起用户的困惑和不安。本文将介绍一些常见的原因和解决方法&#xff0c;以帮助您理解并应对系统安装时间过长的情况。 ​工具/原料&#xff1a; 系统版本&#xff1a;Windows 10 专业版 品…

Python数据攻略-Pandas的数据创建与基础特性

大家好&#xff0c;我是Mr数据杨&#xff01;今天将进入Python的Pandas数据世界&#xff0c;就像三国演义中的英雄们&#xff0c;用聪明才智塑造自己的命运。 记得三国中&#xff0c;周瑜曾利用兵法巧妙策划火烧赤壁&#xff0c;击败曹军。这就像创建一个Pandas DataFrame&…

JavaSE笔记(七)重制版

多线程与反射 前面我们已经讲解了JavaSE的大部分核心内容&#xff0c;最后一章&#xff0c;我们还将继续学习JavaSE中提供的各种高级特性。这些高级特性对于我们之后的学习&#xff0c;会有着举足轻重的作用。 多线程 **注意&#xff1a;**本章节会涉及到 操作系统 相关知识…