当前位置: 首页 > article >正文

Vue.js 响应式原理与数据绑定

在 Vue.js 中,响应式系统是其核心特性之一,它使得数据的变化能够自动更新到 DOM 上,实现了数据和视图的双向绑定。下面详细介绍 Vue.js 响应式系统的原理以及它是如何实现数据绑定的。

原理概述

Vue.js 的响应式系统主要基于 JavaScript 的 Object.defineProperty() 方法(Vue 2.x)和 ES6 的 Proxy 对象(Vue 3.x)来实现。其核心思想是通过拦截数据对象的属性访问和修改操作,当数据发生变化时,自动触发相应的更新操作,从而更新与之绑定的 DOM。

Vue 2.x 响应式原理及数据绑定实现

  1. Object.defineProperty()方法
    Object.defineProperty()方法可以直接在一个对象上定义一个新属性,或者修改一个现有属性的配置,并返回这个对象。它允许我们劫持对象属性的getter和setter方法,从而实现对属性访问和修改的拦截。
  2. 实现步骤
    • 数据劫持: 在创建 Vue 实例时,Vue 会遍历data选项中的所有属性,使用Object.defineProperty()将这些属性转换为getter/setter。
    • 依赖收集: 当一个getter被触发时,意味着有地方在访问这个属性,Vue 会将这个依赖收集起来。
    • 发布更新: 当一个setter被触发时,意味着属性的值发生了变化,Vue 会通知所有依赖该属性的地方进行更新。
  3. 示例代码
// 模拟Vue的响应式系统
function defineReactive(obj, key, val) {// 创建一个Dep对象,用于收集依赖const dep = new Dep();Object.defineProperty(obj, key, {get() {// 收集依赖if (Dep.target) {dep.addSub(Dep.target);}return val;},set(newVal) {if (newVal !== val) {val = newVal;// 通知所有依赖更新dep.notify();}}});
}
// Dep类,用于管理依赖
class Dep {constructor() {this.subs = [];}addSub(sub) {this.subs.push(sub);}notify() {this.subs.forEach(sub => sub.update());}
}
// Watcher类,用于订阅数据变化
class Watcher {constructor(vm, expOrFn, cb) {this.vm = vm;this.cb = cb;Dep.target = this;this.getter = parsePath(expOrFn);this.value = this.get();Dep.target = null;}get() {return this.getter.call(this.vm, this.vm);}update() {const oldValue = this.value;this.value = this.get();this.cb.call(this.vm, this.value, oldValue);}
}
// 解析路径
function parsePath(path) {const segments = path.split('.');return function (obj) {for (let i = 0; i < segments.length; i++) {if (!obj) return;obj = obj[segments[i]];}return obj;};
}
// 使用示例
const data = {message: 'Hello, Vue!'
};
defineReactive(data, 'message', data.message);
const updateDOM = function (newValue, oldValue) {console.log(`数据更新:${oldValue} -> ${newValue}`);
};
new Watcher(data, 'message', updateDOM);
// 修改数据
data.message = 'Hello, World!';

Vue 3.x 响应式原理及数据绑定实现

  1. Proxy对象
    ES6 引入的Proxy对象可以创建一个对象的代理,从而实现对该对象的基本操作的拦截和自定义。相比于Object.defineProperty(),Proxy可以直接监听对象的属性变化,并且可以监听对象的新增和删除属性。
  2. 实现步骤
    • 创建代理: 在创建 Vue 实例时,Vue 会使用Proxy对象对data选项中的对象进行代理。
    • 依赖收集和发布更新: 与 Vue 2.x 类似,当访问代理对象的属性时,会触发getter进行依赖收集;当修改属性时,会触发setter通知所有依赖进行更新。
  3. 示例代码
// 模拟Vue 3.x的响应式系统
function reactive(target) {const handler = {get(target, key) {// 收集依赖track(target, key);return target[key];},set(target, key, value) {target[key] = value;// 通知更新trigger(target, key);return true;}};return new Proxy(target, handler);
}
// 依赖收集
const targetMap = new WeakMap();
function track(target, key) {if (!Dep.target) return;let depsMap = targetMap.get(target);if (!depsMap) {targetMap.set(target, (depsMap = new Map()));}let dep = depsMap.get(key);if (!dep) {depsMap.set(key, (dep = new Set()));}dep.add(Dep.target);
}
// 发布更新
function trigger(target, key) {const depsMap = targetMap.get(target);if (!depsMap) return;const dep = depsMap.get(key);if (dep) {dep.forEach(sub => sub.update());}
}
// Watcher类,用于订阅数据变化
class Watcher {constructor(vm, expOrFn, cb) {this.vm = vm;this.cb = cb;Dep.target = this;this.getter = parsePath(expOrFn);this.value = this.get();Dep.target = null;}get() {return this.getter.call(this.vm, this.vm);}update() {const oldValue = this.value;this.value = this.get();this.cb.call(this.vm, this.value, oldValue);}
}
// 解析路径
function parsePath(path) {const segments = path.split('.');return function (obj) {for (let i = 0; i < segments.length; i++) {if (!obj) return;obj = obj[segments[i]];}return obj;};
}
// 使用示例
const data = reactive({message: 'Hello, Vue 3!'
});
const updateDOM = function (newValue, oldValue) {console.log(`数据更新:${oldValue} -> ${newValue}`);
};
new Watcher(data, 'message', updateDOM);
// 修改数据
data.message = 'Hello, World 3!';

总结

Vue.js 的响应式系统通过Object.defineProperty()(Vue 2.x)或Proxy对象(Vue 3.x)实现了数据劫持,通过依赖收集和发布更新机制实现了数据绑定,使得数据的变化能够自动更新到 DOM 上。

相关文章:

Vue.js 响应式原理与数据绑定

在 Vue.js 中&#xff0c;响应式系统是其核心特性之一&#xff0c;它使得数据的变化能够自动更新到 DOM 上&#xff0c;实现了数据和视图的双向绑定。下面详细介绍 Vue.js 响应式系统的原理以及它是如何实现数据绑定的。 原理概述 Vue.js 的响应式系统主要基于 JavaScript 的…...

爱彼(Audemars Piguet):瑞士制表艺术的巅峰之作(中英双语)

爱彼&#xff08;Audemars Piguet&#xff09;&#xff1a;瑞士制表艺术的巅峰之作 在瑞士高级制表界&#xff0c;Audemars Piguet&#xff08;爱彼&#xff09; 以其大胆创新、卓越工艺和独立家族经营的传统&#xff0c;成为世界顶级腕表品牌之一。作为瑞士“三大制表品牌”之…...

深入理解Elasticsearch集群与分片:原理及配置方案

一、Elasticsearch集群是什么 想象一下&#xff0c;你有海量的数据&#xff0c;比如一个超大型图书馆的所有书籍信息&#xff0c;要是把这些数据都放在一台电脑里&#xff0c;不仅存不下&#xff0c;而且查询起来会超级慢。Elasticsearch集群就像是一个分布式的数据图书馆系统…...

1134. 国王的魔镜

题目 AC代码 #include<bits/stdc.h> using namespace std; bool hw(char s[]) {bool rtrue;int i;for(i0;i<strlen(s)/2;i){if(s[i]!s[strlen(s)-i-1]){rfalse;break;}}return r; } int main() {char s[1005];gets(s);while(hw(s)true&&strlen(s)%20){s[strl…...

【20250215】二叉树:144.二叉树的前序遍历

# 前序遍历-递归-LC144_二叉树的前序遍历 # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, rightNone): # self.val val # self.left left # self.right right # class Solution: # def pre…...

浅说树形dp

文章目录 前言树形dp的转移方式树形dp的使用的场景小结 初步感知——简单的树形dp例题1例题2 深入分析——树形dp的经典模型最大独立集最小点覆盖最小支配集树上直径 前言 因为树的形式非常适合递归&#xff0c;他所带来的访问顺序也是非常符合拓扑排序的&#xff0c;故而在处…...

DeepSeek R1本地部署 DeepSeek Api接口调用 DeepSeek RAG知识库工作流详解

DeepSeek R1本地部署 DeepSeek Api接口调用 DeepSeek RAG知识库工作流详解全集&#xff1a; 第一部分&#xff1a;Windows本地部署DeepSeek R1 第二部分&#xff1a;Macos本地部署DeepSeek R1 第三部分&#xff1a;Linux本地部署DeepSeek R1 第四部分&#xff1a;DeepSeek …...

使用Charles进行mock请求

在 Charles 中&#xff0c;“Compose”&#xff08;构建请求&#xff09;功能允许你手动创建和发送 HTTP 或 HTTPS 请求&#xff0c;方便进行 API 测试、调试等操作。以下是 Compose 功能的详细使用方式&#xff1a; 1. 打开 Compose 界面 启动 Charles 后&#xff0c;在菜单…...

linu软件编程——IO

函数接口 fputc&#xff1a; man 3 fputc 原型&#xff1a;int fputc(int c, FILE *stream); 功能: 向stream流中写入 字符c 参数&#xff1a;c:要写入的字符的ASCII码值 stream:文件流指针 返回值&#xff1a;成功返回写入字符的ASCII码值 失败返回-1 fputc(ch, stdout) put…...

RAMinit 程序编译运行考古记录

本科的时候浅浅研究了DOSBox&#xff0c;今天看到网上挺多关于雷军代码的新闻&#xff0c;我把雷军代码在web上编译出来了&#xff0c;但是我是业余选手&#xff0c;所以做得比较差&#xff0c;不过大家感兴趣可以关注我的dosplay项目&#xff0c;旨在利用js-dos实现汇编语言在…...

2.【线性代数】——矩阵消元

二 矩阵消元 1. 消元法2. 单行或者单列的矩阵乘法2.1 单行矩阵乘法2.2 单列矩阵乘法 3. 用矩阵记录消元过程&#xff08;初等矩阵&#xff09; 【行的线性组合&#xff08;数乘和加法&#xff09;】3.1 row2-3row1的矩阵描述3.2 row3-2row2的矩阵描述3.3 矩阵乘法的性质 4. 用矩…...

Vue 3 30天精进之旅:Day 25 - PWA支持

一、引言 在前面的24天中&#xff0c;我们已经深入探讨了Vue 3的许多核心概念和高级特性。今天&#xff0c;我们将进入一个全新的领域——PWA&#xff08;Progressive Web App&#xff09;。PWA是一种现代Web应用程序的开发模式&#xff0c;它结合了Web和原生应用的优点&#…...

【Pico】使用Pico进行无线串流搜索不到电脑

使用Pico进行无线串流搜索不到电脑 官串方式&#xff1a;使用Pico互联连接电脑。 故障排查 以下来自官方文档 请按照以下步骡排除故障&#xff1a; 确认电脑和一体机连接了相同的路由器WiFi网络(相同网段) IP地址通常为192.168.XX&#xff0c;若两设备的IP地址前三段相同&…...

Golang Model 字段自动化校验设计

背景 在我们日常开发中&#xff0c;不可避免的总要去进行各种参数校验&#xff0c;但是如果在某个场景中&#xff0c;要校验的字段非常多&#xff0c;并且在其中还有耦合关系&#xff0c;那么我们手写校验逻辑就变得非常的低效且难以维护。本篇文档就基于 DDD 领域模型设计的思…...

移动端测试的挑战与解决方案:兼容性、网络问题及实战策略

引言 移动应用已成为用户触达服务的核心入口,但移动端测试面临设备多样性、网络波动、用户场景复杂等多重挑战。据Statista统计,2023年全球活跃移动设备超180亿台,操作系统(Android/iOS)版本碎片化率超30%,这对测试工程师提出了极高要求。本文深度解析移动端测试的核心痛…...

AI agent 未来好的趋势:AI医疗影像、智能客服、个性化推荐

AI agent 未来好的趋势:AI医疗影像、智能客服、个性化推荐 目录 AI agent 未来好的趋势:AI医疗影像、智能客服、个性化推荐比特币AI Agents稳定币扩容区块链AI基础设施AI驱动的软件应用AI赋能的行业应用AI医疗影像、智能客服、个性化推荐AI药物研发比特币 市场与机构化:2024…...

如何使用Three.js制作3D月球与星空效果

目录 1. 基本设置2. 创建星空效果3. 创建月球模型4. 添加中文3D文字5. 光照与相机配置6. 动画与控制7. 响应式布局8. 结语 在本文中&#xff0c;我们将一起学习如何利用Three.js实现一个3D月球与星空的效果&#xff0c;并添加一些有趣的元素&#xff0c;比如中文3D文字和互动功…...

Spring安装和使用(Eclipse环境)

一、Spring框架概述 1、 什么是Spring Spring是一个开源框架&#xff0c;Spring是于2003 年兴起的一个轻量级的Java 开发框架&#xff0c;由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复…...

网络安全-攻击流程-传输层

传输层攻击主要针对OSI模型的第四层&#xff0c;涉及TCP和UDP协议的安全漏洞。以下是常见攻击类型及其流程&#xff0c;以及防御措施&#xff1a; 1. SYN洪水攻击&#xff08;TCP半连接攻击&#xff09; 攻击流程&#xff1a; 目标选择&#xff1a;确定目标服务器的IP地址和开…...

图论- Dijkstra算法

Dijkstra算法 前言概念BFS基础模版DijkstraDijkstra函数签名State类distTo 记录最短路径伪代码模版第一个问题解答第二个问题解答第三个问题解答 前言 学习这个算法之间,必须要对BFS遍历比较熟悉,它的本质就是一个特殊改造过的BFS算法. 概念 Dijkstra算法是一种计算图中单源…...

CAS单点登录(第7版)9.属性

如有疑问&#xff0c;请看视频&#xff1a;CAS单点登录&#xff08;第7版&#xff09; 属性 属性定义 概述 属性定义 从身份验证或属性存储库源获取和解析 CAS 中属性的定义时&#xff0c;往往使用其名称进行定义和引用&#xff0c;而无需任何其他元数据或修饰。例如&#…...

一些常用的Yum源

一些常用的Yum源 # CentOS-Stream-AppStream.repo [appstream] nameCentOS Stream $releasever - AppStream baseurlhttps://mirrors4.tuna.tsinghua.edu.cn/centos-vault/8-stream/AppStream/x86_64/os/ gpgcheck0 enabled1# CentOS-Stream-BaseOS.repo [baseos] nameCentOS …...

【电路笔记】-双向计数器

双向计数器 文章目录 双向计数器1、概述2、双向计数器双向计数器能够通过任何给定的计数序列向上或向下方向计数。 1、概述 双向计数器是同步向上/向下二进制计数器,能够在两个方向上向或从某个预设值以及零进行计数。 除了从零开始“向上”计数并增加或递增到某个预设值之外…...

Python PyCharm DeepSeek接入

Python PyCharm DeepSeek接入 创建API key 首先进入DeepSeek官网&#xff0c;https://www.deepseek.com/ 点击左侧“API Keys”&#xff0c;创建API key&#xff0c;输出名称为“AI” 点击“创建"&#xff0c;将API key保存&#xff0c;复制在其它地方。 在PyCharm中下…...

LeetCode 232: 用栈实现队列

LeetCode 232: 用栈实现队列 题目描述 使用栈实现队列的操作。支持以下操作&#xff1a; MyQueue()&#xff1a;初始化队列。push(x)&#xff1a;将元素 x 推入队列。pop()&#xff1a;从队列中移除元素。peek()&#xff1a;返回队列头部的元素。empty()&#xff1a;检查队列…...

P6792 [SNOI2020] 区间和 Solution

Description 给定序列 a ( a 1 , a 2 , ⋯ , a n ) a(a_1,a_2,\cdots,a_n) a(a1​,a2​,⋯,an​)&#xff0c;有 m m m 个操作分两种&#xff1a; chmax ⁡ ( l , r , v ) \operatorname{chmax}(l,r,v) chmax(l,r,v)&#xff1a;对每个 i ∈ [ l , r ] i \in [l,r] i∈[l,…...

基于智能体和RWA的分布式商业生态商业模型架构设计

引言 在数字化和智能化的浪潮下&#xff0c;传统商业生态正经历着深刻的变革。如何通过技术的赋能推动商业模式的升级&#xff0c;成为各行各业的共识。**智能体&#xff08;AI Agents&#xff09;与现实世界资产&#xff08;RWA&#xff09;**的结合&#xff0c;为分布式商业生…...

从ARM官方获取自己想要的gcc交叉编译工具链接(Arm GNU Toolchain),并在Ubuntu系统中进行配置

前言 本文是博文 https://blog.csdn.net/wenhao_ir/article/details/145547974 的分支博文。 在本博文中我们完成gcc交叉编译工具gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf.tar.xz的下载、配置、测试。 下载自己想要的gcc交叉编译工具的源码 目标文件的名字及说…...

Linux上Elasticsearch 集群部署指南

Es 集群部署 Es 集群部署 Es 集群部署 准备好三台服务器。示例使用&#xff1a;110.0.5.141/142/143 1、es用户和用户组创建&#xff0c;使用root账号 groupadd esuseradd -g es es2、将es安装包和ik分词器上传到&#xff1a;/home/es/目录下&#xff08;任意目录都行&#…...

【系统架构设计师】虚拟机体系结构风格

目录 1. 说明2. 解释器体系结构风格3. 规则系统体系结构风格4. 例题4.1 例题1 1. 说明 1.p263。2.虚拟机体系结构风格的基本思想是人为构建一个运行环境&#xff0c;在这个环境之上&#xff0c;可以解析与运行自定义的一些语言&#xff0c;这样来增加架构的灵活性。3.虚拟机体…...